• 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不会执行则不会返回,于是主线程一直堵塞。造成死锁。
  • 相关阅读:
    luogu1525 [NOIp2011]关押罪犯 (并查集)
    luogu1084 [NOIp2012]疫情控制 (二分答案+倍增+dfs序)
    luogu1083 [NOIp2012]借教室 (二分答案+差分)
    bzoj4152 The Captain (dijkstra)
    luogu1081 [NOIp2012]开车旅行 (STL::multiset+倍增)
    suoi22 WRX知识树(dfs序)
    [HNOI2010]弹飞绵羊
    1596: [Usaco2008 Jan]电话网络
    [Tyvj Jan]青蛙跳荷叶
    [BZOJ1116] CLO
  • 原文地址:https://www.cnblogs.com/zhangmaliang/p/5146946.html
Copyright © 2020-2023  润新知