美文网首页Runtime
iOS深入理解property之getter

iOS深入理解property之getter

作者: 笨鱼BennettPenn | 来源:发表于2018-10-18 19:30 被阅读24次

    前言

    一直以来都有去通过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方法,并没有具体的赋值实现的。困惑。。。

    相关文章

      网友评论

        本文标题:iOS深入理解property之getter

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