本章内容
- WWDC2020针对runtime进行的三项优化
- 类的加载方式是什么方式(懒加载)
- 实例变量,属性,成员变量区别
- copy与其他修饰符是哪的地方不同
- objc_setProperty方法在底层是什么情况下调用的
- 方法的编码
- runtime的几个方法
类的加载方式
这次只进行简单的验证,验证类的加载方式是懒加载
模式,至于为什么以及原理是什么先不做深究。例如:继承关系:Teacher -> Person -> NSObject。
注意我们的验证流程实在objc源码工程进行验证,脱离源码环境的情况需要自行去取样,也就是把源码复制一份到工程
流程:
Person类指针地址 —-> 平移0x20得到bits —-> 调用class_rw_t* data() 获取class_rw_t* —-> 输出class_rw_t结构查看 —–> 调用Teacher.class方法 —->输出class_rw_t结构查看
验证:
1、进行LLDB调试执行代码 Person *p = [Person alloc]
就发现在类Person的结构中,其第四个成员是bits,它的本质是class_data_bits_t 的结构体指针,通过bits我们可以获取class_rw_t结构体指针,如有疑问请看类的本质然后查看到firstSubclass为空。
补充:nextSiblingClass
代表内存中与Person类相邻的类是NSUUID
2、执行[Teacher class]
然后查看Person的class_rw_t,发现firstSubclass显示为Teacher
实例变量,属性,成员变量
1、属性:为ivar + setter + getter,也就是成员变量 + 系统为属性自动生成的setter和getter方法
2、成员变量:只是单纯的ivar,例如:int, char, double, float, string, bool等类型。在底层编译是常规数据类型的
3、实例变量:特殊的成员变量,例如NSObject类型,可以认为在底层编译是结构体的
验证:用clang进行验证
例如:我们创建的Person类
转为cpp文件以后查看
修饰符copy的特殊之处
我们一提起copy就说它是拷贝,如果对象要实现深拷贝就要实现NSMutableCopying协议,如果要实现浅拷贝就要实现NSCopying协议,然后深拷贝拷贝的是内容,浅拷贝拷贝的是指针,也就是指针引用。附深浅拷贝
1、查看Person类
分别定义了5种不同的属性
2、查看经过clang转换的C++源码
1、看了对象Person的结构
2、看属性nonatomic_strong_name的setter和getter方法,得到strong修饰的是属性是isa+内存平移得到。
3、看属性nonatomic_copy_name的setter和getter方法,得到copy修饰的是属性,getter方法是isa+内存平移,setter是调用了objc_setProperty
方法
4、看属性nonatomic_name的setter和getter方法,跟strong一样是isa+内存平移得到
5、看属性atomic_copy_name的setter和getter方法,得到getter方法是调用了objc_getProperty方法,setter方法是调用了objc_setProperty方法
6、看属性atomic_name的setter和getter方法,跟strong一样是isa+内存平移得到
3、疑问与总结
疑问:为什么属性nonatomic_copy_name与atomic_copy_name同其他属性不一样呢,为什么会调用objc_setProperty方法呢,又为什么atomic和copy一起修饰的时候又会调用objc_getProperty方法呢
总结:如果用copy修饰的属性setter方法一定会调用objc_setProperty,而更特殊但不经常用的修饰方式(atomic和copy)会调用objc_getProperty。这是因为在苹果编译框架LLVM层的时候就根据这两个属性进行了判断。在这里只演示LLVM结果
4、objc_setProperty的objc源码是怎么回事
其实不止是objc_setProperty
还有objc_setProperty_atomic
、objc_setProperty_atomic
、objc_setProperty_nonatomic
、objc_setProperty_atomic_copy
、objc_setProperty_nonatomic_copy
等6个方法都指向了最终一个方法—–> reallySetProperty
。
注意:请看atomic的条件判断,得知在底层的原子性就是加了个锁而已,为了读取安全,但是读取安全并不代表线程安全。有个面试题会经常被问到atomic真的线程安全吗?答案是不一定的,例如:异步线程A进行赋值,线程B进行读取,里面各自的操作循环很多次。
5、objc_getProperty的objc源码是怎么回事
方法的编码
在LLDB进行查看方法的输出的时候,我们经常看到一些编码例如:
- v 代表返回类型 void
- 16 代表方法参数总和需要的字节大小 16字节
- @ 代表第一个参数类型是id类型
- 0 代表第一个参数从字节0号位开始
- : 代表第二个参数类型 SEL
- 8 代表第二个参数从字节8号位开始
总结:每一个字符都代表了不同的编码。编码对照表进行查看。
runtime的几个方法
以下内容是我自己的笔记内复制过来的,将就着看