.
当我们在@property上加上strong和copy关键字以后,编译器都为我们做了什么?
1. 实例代码
1 | @interface HRObject : NSObject |
1 | xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m -o arm64.cpp |
2. 编译后源码
1 | int main(int argc, const char * argv[]) { |
可以看到我们在使用点语法的时候,最终是生成了相应的set方法setStrongName:
和setWeakName:
,找到这两个方法的实现,_INSTANCE_METHODS_HRObject
给所有参数都申请了Setter
和Getter
方法。而object.weakName = @"weak";
最终调用的是_I_HRObject_setWeakName_
方法。
1 | static struct /*_method_list_t*/ { |
_I_HRObject_setWeakName_
最终调用的是objc_setProperty
1 | static void _I_HRObject_setWeakName_(HRObject * self, SEL _cmd, NSString *weakName) { objc_setProperty (self, _cmd, __OFFSETOFIVAR__(struct HRObject, _weakName), (id)weakName, 0, 1); } |
3.Runtime源码
申明
1 | /* Properties */ |
Getter
Getter方法的逻辑比较简单,判断是否有加锁,没有的话,直接返回变量的值,有的话则先加锁。
1 | id objc_getProperty(id self, SEL _cmd, ptrdiff_t offset, BOOL atomic) { |
Setter
1 | void objc_setProperty_atomic(id self, SEL _cmd, id newValue, ptrdiff_t offset) { |
1 | void objc_setProperty(id self, SEL _cmd, ptrdiff_t offset, id newValue, BOOL atomic, signed char shouldCopy) { |
1 | static inline void reallySetProperty(id self, SEL _cmd, id newValue, ptrdiff_t offset, bool atomic, bool copy, bool mutableCopy) { |
4. 成员变量的Offset是怎么计算的?
The sequence of operations can be illustrated in the following way:
1 | 1. 0 |
- 定义数字0。
- 将数字0转换成指向
struct Type
的指针。也就是把Type的起始位置转变成0。 - 获取结构体
Type
的变量MEMBER
。 - 但是并没有使用
MEMBER
的值,使用的是MEMBER
的内存地址。 - 最终又把地址转换成了
size_t
的类型。
因为这个结构体的起始位置被指定为0,所以MEMBER
的地址转换成数字的时候,就是MEMBER
基于struct
的偏移量。
这个特定代码无害的原因是没有写入,甚至没有访问过内存位置。 一切都只涉及指向这些位置(而不是它们的内容)和数字的指针。 所有这些都保存在机器寄存器或通常的本地堆栈中。