美文网首页
runtime(一)

runtime(一)

作者: dandelionYD | 来源:发表于2019-03-29 20:52 被阅读0次

    面试题:

    1.OC的消息机制
    析:
    OC中的方法调用其实都是转成objc_msgSend函数的调用,给receiver(方法调用者)发送一条消息(selector方法名)
    objc_msgSend底层有3大阶段:消息转发(当前类、父类中查找)、动态方法解析、消息转发
       
    2.什么是runtime?平时项目中有用过?
    析:
    OC是一门动态性比较强的编程语言,允许很多操作推迟到程序运行时再进行
    OC的动态性就是Runtime来支撑和实现的,Runtime是一套C语言的API,封装了很多动态性相关的函数
    平时编写的OC代码,底层都是转换成了RuntimeAPI进行调用
    
    3.具体应用
    析:
    l.利用关联对象(AssociatedObject)给分类添加属性
    2.遍历类的所有成员变量(修改textFiled的占位文字颜色、字典转模型、自动归档解档)
    3.交换方法实现(交换系统的 方法)
    4.利用消息转发机制解决方法找不到的异常问题
    5. ...
    
    

    本文Demo代码见gitHubDemo

    补充:

    1.&可以用来取出特定的位 (取值)
     0000 0111
    &0000 0100
    ------------
     0000 0100
     
    2.宏定义【掩码,一般用来按位与(&)运算的】
    #define myA 1
    #define myB 2
    #define myC 4
    
    改进:
    #define myA 0b00000001
    #define myB 0b00000010
    #define myC 0b00000100
    
    最终改良版:
    #define myA (1<<0)
    #define myB  (1<<1)
    #define myC  (1<<2)
    

    需求:将对象里面的tall,rich,handsome放在一个字节里面(char)

    myPerson.h
    #import <Foundation/Foundation.h>
    @interface myPerson : NSObject
    - (void)setTall:(BOOL)tall;
    - (void)setRich:(BOOL)rich;
    - (void)setHandsome:(BOOL)handsome;
    - (BOOL)isTall;
    - (BOOL)isRich;
    - (BOOL)isHandsome;
    @end
    
    myPerson.m
    #import "myPerson.h"
    #define myTallMask (1<<0)
    #define myRichMask (1<<1)
    #define myHandsomeMask (1<<2)
    @interface myPerson(){
        char _tallRichHansome;
    }
    @end
    
    @implementation myPerson
    - (instancetype)init{
        if (self = [super init]) {
            _tallRichHansome = 0b00000100;   //tall 0 ,  rich 0 , handsome 1
        }
        return self;
    }
    
    - (void)setTall:(BOOL)tall{
        if (tall) {
            _tallRichHansome |= myTallMask; //设位为1值(或运算   要运算的那位为1,其他的为0)
            //0b **** **** | 0b 0000 0001 => 0b **** ***1
        } else {
            _tallRichHansome &= ~myTallMask; //设位为0值(与运算   要运算的那位为0,其他的为1)
            //0b **** **** & 0b 1111 1110 => 0b **** ***0
        }
    }
    
    - (BOOL)isTall{
        return !!(_tallRichHansome & myTallMask);
        //0b **** ***X & 0b 0000 0001 ==> 0b 0000 000X
    }
    
    - (void)setRich:(BOOL)rich{
        if (rich) {
            _tallRichHansome |= myRichMask;
        } else {
            _tallRichHansome &= ~myRichMask;
        }
    }
    
    - (BOOL)isRich{
        return !!(_tallRichHansome & myRichMask);
    }
    
    - (void)setHandsome:(BOOL)handsome{
        if (handsome) {
            _tallRichHansome |= myHandsomeMask;
        } else {
            _tallRichHansome &= ~myHandsomeMask;
        }
    }
    
    - (BOOL)isHandsome{
        return !!(_tallRichHansome & myHandsomeMask);
    }
    @end
    
    【main】
    myPerson *person = [[myPerson alloc] init];
    person.rich = YES;
    person.tall = NO;
    person.handsome = YES;
    NSLog(@"tall:%d rich:%d hansome:%d", person.isTall, person.isRich, person.isHandsome);
    打印:tall:0 rich:1 hansome:1
    

    位域

    myPerson.h
    #import <Foundation/Foundation.h>
    @interface myPerson : NSObject
    - (void)setTall:(BOOL)tall;
    - (void)setRich:(BOOL)rich;
    - (void)setHandsome:(BOOL)handsome;
    - (BOOL)isTall;
    - (BOOL)isRich;
    - (BOOL)isHandsome;
    @end
    
    myPerson.m
    #import "myPerson.h"
    @interface myPerson(){
        // 位域
        struct {
            char tall : 1;//占一位(倒数第一位)
            char rich : 1;//占一位(倒数第二位)
            char handsome : 1;//占一位 (倒数第三位)
        } _tallRichHandsome;  // 0b0000 0000
    }
    @end
    
    @implementation myPerson
    - (void)setTall:(BOOL)tall{
        _tallRichHandsome.tall = tall;
    }
    
    - (BOOL)isTall{
        return !!_tallRichHandsome.tall;
    }
    
    - (void)setRich:(BOOL)rich{
        _tallRichHandsome.rich = rich;
    }
    
    - (BOOL)isRich{
        return !!_tallRichHandsome.rich;
    }
    
    - (void)setHandsome:(BOOL)handsome{
        _tallRichHandsome.handsome = handsome;
    }
    
    - (BOOL)isHandsome{
        return !!_tallRichHandsome.handsome;
    }
    @end
    
    【main】
    myPerson *person = [[myPerson alloc] init];
    person.rich = YES;
    person.tall = NO;
    person.handsome = YES;
    NSLog(@"tall:%d rich:%d hansome:%d", person.isTall, person.isRich, person.isHandsome);
    打印:tall:0 rich:1 hansome:1
    

    共同体(类似苹果官方做法)

    myPerson.h
    @interface myPerson : NSObject
    - (void)setTall:(BOOL)tall;
    - (BOOL)isTall;
    - (void)setRich:(BOOL)rich;
    - (BOOL)isRich;
    - (void)setHandsome:(BOOL)handsome;
    - (BOOL)isHandsome;
    - (void)setThin:(BOOL)thin;
    - (BOOL)isThin;
    @end
    
    myPerson.m
    #import "myPerson.h"
    #define myTallMask (1<<0)
    #define myRichMask (1<<1)
    #define myHandsomeMask (1<<2)
    #define myThinMask (1<<3)
    
    @interface myPerson(){
        union {
            int bits;
            struct {
                char tall : 1;
                char rich : 1;
                char handsome : 1;
                char thin : 1;
            };//仅仅是增加可读性,可删除
        } _tallRichHandsome;
    }
    @end//如果不止4位了,那么不够了就改 int 类型了
    
    @implementation myPerson
    - (void)setTall:(BOOL)tall{
        if (tall) {
            _tallRichHandsome.bits |= myTallMask;
        } else {
            _tallRichHandsome.bits &= ~myTallMask;
        }
    }
    
    - (BOOL)isTall{
        return !!(_tallRichHandsome.bits & myTallMask);
    }
    
    - (void)setRich:(BOOL)rich{
        if (rich) {
            _tallRichHandsome.bits |= myRichMask;
        } else {
            _tallRichHandsome.bits &= ~myRichMask;
        }
    }
    
    - (BOOL)isRich{
        return !!(_tallRichHandsome.bits & myRichMask);
    }
    
    - (void)setHandsome:(BOOL)handsome{
        if (handsome) {
            _tallRichHandsome.bits |= myHandsomeMask;
        } else {
            _tallRichHandsome.bits &= ~myHandsomeMask;
        }
    }
    
    - (BOOL)isHandsome{
        return !!(_tallRichHandsome.bits & myHandsomeMask);
    }
    
    - (void)setThin:(BOOL)thin{
        if (thin) {
            _tallRichHandsome.bits |= myThinMask;
        } else {
            _tallRichHandsome.bits &= ~myThinMask;
        }
    }
    
    - (BOOL)isThin{
        return !!(_tallRichHandsome.bits & myThinMask);
    }
    @end
    
    【main】
    myPerson *person = [[myPerson alloc] init];
    person.rich = YES;
    person.tall = NO;
    person.handsome = YES;
    NSLog(@"tall:%d rich:%d hansome:%d", person.isTall, person.isRich, person.isHandsome);
    打印:tall:0 rich:1 hansome:1
    

    isa详解/位域

    • isa详解
      • 要想学习runtime,首先要了解它底层的一些常用数据结构,比如isa指针
      • 在arm64架构之前,isa就是一个普通的指针,存储着Class、Meta-Class对象的内存地址
      • 从arm64架构之后,对isa进行了优化,变成一个共同体(union)结构,还使用位域来存储更多的信息


        runtime_01.png
    runtime_02.png

    根据上面2图 :整合如下(arm64)

    union isa_t {
        isa_t() { }
        isa_t(uintptr_t value) : bits(value) { }
    
        Class cls;
        uintptr_t bits;
        
        struct {
          uintptr_t nonpointer        : 1;                                       
          uintptr_t has_assoc         : 1;                                       
          uintptr_t has_cxx_dtor      : 1;                                       
          uintptr_t shiftcls          : 33; /*MACH_VM_MAX_ADDRESS 0x1000000000*/ 
          uintptr_t magic             : 6;                                       
          uintptr_t weakly_referenced : 1;                                       
          uintptr_t deallocating      : 1;                                       
          uintptr_t has_sidetable_rc  : 1;                                       
          uintptr_t extra_rc          : 19
        };
    };
    总共:1+1+1+33+6+1+1+1+19 = 64 位
    

    说明:(isa位域)

    1.nonpointer
      0:代表普通的指针,存储着Class、Meta-Class对象的内存地址
      1:代表优化过,使用位域存储更多的信息
      
    2.has_assoc
      是否有设置过关联对象,如果没有,释放时会更快
      
    3.has_cxx_dtor
      是否有C++的析构函数(.cxx_destruct),如果没有释放时会更快
     
    4.shiftcls
        存储着Class、Meta-Class对象的内存地址信息
    
    5.magic
        用于在调试时分辨对象是否未完成初始化
    
    6.weakly_referenced
        是否有被弱引用指向过,如果没有,则释放时会更快
        
    7.deallocating
        对象是否正在释放 
        
    8.has_sidetable_rc
        引用计数器是否过大无法存储在isa中
        如果为1,那么引用计数会存储在一个叫SideTable的类的属性中
        
    9.extra_rc
        里面存储的值是引用计数器减1
    

    枚举或

    myPerson.h
    #import <Foundation/Foundation.h>
    typedef enum {
        OptionsOne = 1<<0, // 0b 0000 0001
        OptionsTwo = 1<<1, // 0b 0000 0010
        OptionsThree = 1<<2,//0b 0000 0100
        OptionsFour = 1<<3 // 0b 0000 1000
    } Options;
    @interface myPerson : NSObject
    @property(nonatomic,assign)Options option;
    @end
    
    myPerson.m
    #import "myPerson.h"
    
    @implementation myPerson
    -(void)setOption:(Options)option{
        if (option & OptionsOne) {
            NSLog(@"包含了OptionsOne");
        }
        
        if (option & OptionsTwo) {
            NSLog(@"包含了OptionsTwo");
        }
        
        if (option & OptionsThree) {
            NSLog(@"包含了OptionsThree");
        }
        if (option & OptionsFour) {
            NSLog(@"包含了OptionsFour");
        }
    }
    @end
    
    【main】
    #import <Foundation/Foundation.h>
    #import "myPerson.h"
    
    int main(int argc, const char * argv[]) {
        @autoreleasepool {
            myPerson *p = [[myPerson alloc]init];
            p.option = OptionsOne | OptionsTwo | OptionsThree | OptionsFour;
        }
        return 0;
    }
    

    友情链接:

    相关文章

      网友评论

          本文标题:runtime(一)

          本文链接:https://www.haomeiwen.com/subject/rbnrbqtx.html