在clang编译的cpp文件中可以发现 strong & copy & weak 修饰的属性在编译的底层代码中是有区别的
strong & copy & weak 底层分析
- 在LGPerson中我们定义了两个两个属性,分别用copy和strong修饰
- 用
clang
将main.m
文件编译成main.cpp
,然后发现copy 和strong
修饰的属性的set
方法是有区别的
这里就有疑问了,为什么copy修饰的属性使用了objc_setProperty,而strong修饰的没有
?
- 在LLVM中搜索
”objc_setProperty
,找到如下所示的getOptimizedSetPropertyFn
方法中
- 从这里即可看出,针对不同的修饰符,返回的那么是不同的
- 如果是
atomic & copy
修饰,name为objc_setProperty_atomic_copy
- 如果是
atomic 且没有copy
修饰,name为objc_setProperty_atomic
- 如果是
nonatomic & copy
修饰,name为objc_setProperty_nonatomic_copy
- 其他剩余的组合,即
nonatomic、nonatomic & strong、nonatomic & weak
等,name为objc_setProperty_nonatomic
上述的几个name分别对应objc-781源码中的如下方法
然后通过汇编调试发现,最终都会走到objc_storeStrong
- copy修饰的属性汇编调试结果
strong修饰的属性汇编调试结果
- 源码中搜索
objc_storeStrong
,有如下源码,主要也是retain新值,release旧值
void objc_storeStrong(id *location, id obj) { id prev = *location; if (obj == prev) { return; } objc_retain(obj);//retain新值 *location = obj; objc_release(prev);//release旧值 }
llvm编译源码中搜索objc_storeStrong
,找到EmitARCStoreStrongCall
方法,如下图所示,发现copy 和 strong修饰的属性执行的策略是不一致的
llvm中搜索EmitARCStoreStrongCall
方法,在GenerateCopyHelperFunction
方法有调用,然后在这里发现了strong 和 weak的不同处理
其中BlockCaptureEntityKind有如下的枚举值以及表示的含义
如果是weak修饰,执行EmitARCCopyWeak
方法,如下所示,weak在底层的调用是 objc_initWeak
- 如果是strong修饰,执行
EmitARCStoreStrongCall
方法
结论
copy
和strong
修饰的属性在底层编译的不一致,主要还是llvm中对其进行了不同的处理的结果。copy
的赋值是通过objc_setProperty
,而strong的赋值时通过self + 内存平移
(即将指针通过平移移至name所在的位置,然后赋值),然后还原成strong
类型strong & copy
在底层调用objc_storeStrong
,本质是新值retain,旧值release
weak
在底层调用objc_initWeak
补充知识: Type Encoding & Property Type String
clang中的方法签名
Type encoding
clang中编译后,方法列表的这些字符的含义是什么
clang编译后的方法列表
以@16@0:8
为例
- @16表示返回字符串占用16个字节 -- 第二个
@
占8
字节,sel
占8
字节
第一个@
表示返回值
16
表示 总共占用的字节数16
字节- 第二个@:第一个参数
- id -- @ 统配类型
- typedef struct objc_object *id
- 0 -- 从0开始 0-8
- : -- 代表sel,方法编号
- 8 -- 8-16
- 而v24@0:8@16中的 v -- void 无返回值
更多的可以查看官网的以下列表
Type encoding表
clang编译后的属性的attribute
clang编译输出了属性的attribute
,同样也可以通过property_getAttributes
方法获取
T
表示type
@
表示变量类型
C
表示copy
N
表示nonatomic
V
表示variable
变量,即下划线变量_nickName
更多的可以查看官网的以下列表