美文网首页
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