OC深入知识点

  这两个月看了些OC底层一点的东西,还是有很多不明白的,为了加深印象,记录如下:

1、对象A的引用计数值存储于一张全局散列表中(未考虑tagged pointer优化),以A的地址&A为key,引用计数值减1为value。当A进行retain时,在全局散列表中根据&A找到对应的引用计数值,将其加1。

2、__weak修饰的所有对象存储于一张全局散列表中,例如A对象,若有__weak obj1 = A; __weak obj2 = A,则散列表中用&A为键,以一个类似数组的对象为value,该数组对象中存储了obj1和obj2。当A对象销毁时,到散列表中以&A为值找到对应数组,取出其中的obj1和obj2,将其指针清空为nil。

3、__weak修饰符只持有对象的弱引用,当在访问弱引用对象过程中,该对象有可能被废弃,存在危险。故当我们访问__weak修饰的对象时,系统会自动将其注册到autorelease中,保证我们在使用过程中该对象的生命周期。每一次访问弱引用对象都会将该对象注册进自动释放池一次,浪费性能。故现在流行如下写法。一来保证block执行过程中对象一定存在,二来不再重复访问弱引用修饰的对象,避免重复注册该对象到自动释放池。

 1     NSObject *obj = [NSObject new];
 3     __weak typeof(obj) weakObj = obj;
 5     void (^blk)() = ^{
 7         __strong typeof(weakObj) strongObj = obj;
 9         if (strongObj) {
10             NSLog(@"%@",strongObj);
11         }
12     };
14     blk();

4、代码片段

{
      id obj = [NSMutableArray array];      
}

  上面用编译器模拟runtime代码可转换为如下: 

    id obj = objc_msgSend(NSMutableArray,@selector(array));
    objc_retainAutoreleasedReturnValue(obj);
    obj_release(obj)

  解读:对数组类NSMutableArray发送@selector(array)消息创建对象obj,retain对象让其存活,退出作用域销毁

    而类方法+(id)array的实现则为

+ (id)array{
    return [[NSMutableArray alloc] init];
}

  模拟转换如下

+ (id)array{
    id obj = objc_msgSend(NSMutableArray,@selector(array));
    objc_msgSend(obj,@selector(init));
    return objc_autoreleaseReturnValue(obj);
}

  解读:创建数组对象obj,将其放到自动释放池中后返回

  纵观上面解析,发现数组对象创建后放到自动释放池中,然后retain,此时引用计数值为2。退出作用域强引用指针obj释放,则引用计数器减一。当此次runloop结束后自动释放池清空,数组对象再次release,引用计数器为0数组销毁。从代码上来看,该数组放入自动释放池跟retain完全没有必要,生成对象直接强指针持有,退出作用域销毁即可。

  以下objc_autoreleaseReturnValue(): 用符号A代替、 objc_retainAutoreleasedReturnValue(): 用符号B代替

  runtime优化:A和B总是成对出现,A总在B之前。对方法A和B进行了特殊处理,让其在如上情况下不是将对象放入自动释放池和将对象retain,而是动态判断,当发现A方法后紧随着B方法,则A方法不再将对象放入自动释放池,而是将一个标记为flag设置为YES。对B方法,检查标志位flag,若发现其位YES,则不再将对象retain,而只是将标记为flag重置为NO,省去两次操作。伪代码如下:

 1 static BOOL flag = NO;
 2 id objc_autoreleaseReturnValue(obj){
 3     if (@"后面紧跟着B方法") {
 4         flag = YES;
 5     }else{
 6         [obj autorelease];
 7     }
 8     return obj;
 9 }
10 
11 void objc_retainAutoreleasedReturnValue(obj){
12     if (flag) {
13         flag = NO;
14     }else{
15         [obj retain];
16     }
17 }

5、runtime一般用途

  a、数据绑定,主要函数objc_setAssociatedObject和objc_getAssociatedObject,主要用于分类属性扩充

  b、查看系统类的私有成员变量以及私有方法,可以针对系统私有变量进行KVC赋值。

  c、黑盒方法method swizzling,跟换系统方法实现,比如在所有控制器的viewWillAppear和viewDidDisappear方法中添加友盟统计方法,统计页面停留时间

6、KVO实现原理:观察A对象的progress属性,系统动态创建A的子类B,将A的isa指针指向B,重写对象B的setProgress方法,在里面发出如下通知,通知观察者的相应方法

- (void)setPregress: (CGFloat )progress{
    [self willChangeValueForKey:@"progress"];
    _progress = progress;
    [self didChangeValueForKey:@"progress"];
}

 7、同步线程死锁。如下代码在主线程执行会死锁

    dispatch_sync(dispatch_get_main_queue(), ^{
        NSLog(@"会死锁");
    });
  同步函数dispatch_sync在block返回之前会一直卡住线程。若当前代码在主线程执行,则主线程在block返回之前一直会是堵塞状态。而block恰好是在主线程执行,而主线程被堵塞,于是blcok不会执行,block不会执行则不会返回,于是主线程一直堵塞。造成死锁。
原文地址:https://www.cnblogs.com/zhangmaliang/p/5146946.html