iOS深入理解property之getter

前言

一直以来都有去通过blog去了解一下技术的问题,但是因为blog毕竟是别人消化的东西,在作者阅读相关资料 -> 消化 -> blog文字输出 -> 自己读blog -> 自己消化,这是一个很长的信息链,而这个链接每一个环节都存在信息漏斗,到最终到自己消化的时候,可能和信息最初的样子,会有比较大的偏差了。

还有另外一个问题就是,读取别人的blog,自己没有亲身实践过,看的时候理解了,但是总是不深刻,到后面遇到这个知识点的时候,需要比较长的时间去慢慢回忆起来,组合成一个大概的信息具象,没有一个系统的了解。

高中的时候,数学老师一直在强调好记性不如烂笔头,一直叫我们就算看懂了,你写下来之后理解会加深,现在深有体会。现在不是好记性不如烂笔头,像我这种记性不好的,需要烂键盘的!!

所以,在以后的工作还是需要作出一点点改变,看到需要不理解的知识点,是需要从信息的根来源进行寻根问题,并且记下来用文字表达一次,才能对相关知识点有一个系统行的理解。

吃过的亏,要接受教训啊!

所以这篇文章是在理解property,是从runtime和CoreFoundation出发去理解,理解其原理,能有更深刻的理解。

runtime的getter实现

在很多书籍或者blog里面,都有解析到Objective-C中各个修饰属性的区别,因为都是一个结论给出,并没有理解里面的具体实现,所以并不深刻。所以,在runtime层面查看对象属性赋值的实现。

在runtime的源代码中,在Private Header下的objc_abi.h文件中,可以找到对象属性读写的abi定义,而实际的实现代码存放在objc-accessors.mm文件中。由于这是私有abi,在iOS的SDK里面的/usr/include/目录下并不能看到这些信息。如果需要查看这个定义,需要在runtime的源代码才能看到。

在这个objc-accessors.mm文件中,先看getter方法对应的实现:

//getter函数参数与定义的修饰词相关的就只有atomic修饰词
//也就是说除了atomic修饰词和nonatomic修饰词,copy、assign、strong、weak修饰词都并无相关
id objc_getProperty(id self, SEL _cmd, ptrdiff_t offset, BOOL atomic) {
    if (offset == 0) {
        return object_getClass(self);
    }

    // Retain release world
    id *slot = (id*) ((char*)self + offset);//计算属性所在的指针偏移量
    if (!atomic) return *slot;//如果是非原子性操作,直接返回属性的对象指针
    //原子性操作,则继续执行
    
    //获取属性锁,属性锁的定义是这样的
    //PropertyLocks是一个StripedMap<spinlock_t>类型的全局变量
    //而StripedMap是一个用数组来实现的hashmap,key是指针,value是类型是spinlock_t对象
    //而spinlock_t则是mutex_tt<LOCKDEBUG>的类,而mutex_tt类内部是由os_unfair_lock mLock来实现
    //一言以蔽之,PropertyLocks[slot]目的就是获取os_unfair_lock对象
    spinlock_t& slotlock = PropertyLocks[slot];
    slotlock.lock();//加锁
    id value = objc_retain(*slot);//获取到的对象引用计数+1
    slotlock.unlock();//解锁
    
    // for performance, we (safely) issue the autorelease OUTSIDE of the spinlock.
    //将获取到的对象注册到自动释放池中,保证值能一定获取到,所以是线程安全的
    return objc_autoreleaseReturnValue(value);
}

从函数名上就很清晰的看出来属性修饰词对应的方法,而且就是标准的objc中函数调用时,使用objc_msgSend函数进行函数调用的函数格式。前面两个是隐含参数id和_cmd,后面是函数的实际参数。

通过上述解析,那么可以总结一下getter的特性了:

  • getter获取属性值,copy、assign、strong、weak修饰词无相关,只与atomic和nonatomic修饰词有关
  • 使用nonatomic修饰词,获取到属性值后立马返回,效率高
  • 使用atomic修饰的属性,获取过程会有加锁解锁过程,会有性能的损耗
  • 使用atomic修饰的属性,会将对象注册到自动释放池中

这就是runtime环境中getter的是整个过程,相对于setter来说,比较简单。

最后的最后

上面的分析是基于属性赋值的猜测,在objc源代码的全局并没有搜索到objc_getProperty函数的调用方。在runtime中,所有的函数调用都是通过objc_msgSend函数来进行调用的,通过selector方法选择器来获取真正的IMP函数指针来执行最终的实现。而在objc源代码中,貌似没有找到IMP的定义,所以以上的分析都是基于猜测的。

今天终于将iMac降级了,能抛弃objc源代码的工程,但是写debug代码后在objc_getProperty打了断点,发现并没有调用到objc_getProperty函数,这就很困惑了。因为在调用Foundation层的setter方法,并没有具体的赋值实现的。困惑。。。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 各位亲爱的家长 为了帮助孩子对初中和高中做一个好的衔接,教给孩子学习高中内容的方法和技巧,目前稻谷教育开...
    稻谷龙阅读 174评论 0 0
  • 高中的时候,迷茫,空虚,从根上就是飘着的。爸爸妈妈保护的很好,以为生活很容易,然后衣来伸手饭来张口,养成了懒毛病。...
    王啊啊啊啊增阅读 459评论 1 2
  • 看表,六点五十,选修老师再次放了鸽子。 这师傅怕是被妖怪抓走了,开课两周连面都没见到。 好脾性的我在座位看了一个小...
    抓星星的小超阅读 409评论 1 3
  • 1.苏月白 前年镇上来了个白发青年,住在里镇上不远的荒屋里!很多人都在议论他,说年纪轻轻就这...
    白发月舞阅读 622评论 0 0
  • 人不一定要跨过没一座山丘才能说自己是英雄 人不一定要横跨多少片海域才能说自己有传奇 人不一定要经历多少的故事才能说...
    嘿你的花阅读 132评论 0 2