引言
上篇文章,通过lldb
调试,找到了类的属性、成员变量、实例方法和类方法的存放位置。本文将讲述属性的补充内容。
demo
firstSubclass
上次我们在lldb
调试过程中,发现这个firstSubclass
都是为nil的情况,接下来,我们将讲述为什么。
上代码(QLDog
继承于QLPerson
):
@interface QLDog : QLPerson
@end
main.m文件
int main(int argc, const char * argv[]) {
@autoreleasepool {
QLPerson *person = [QLPerson alloc];
NSLog(@"%@",person);
}
return 0;
}
操作过程如下:
image.png根据上图操作流程,我们可以看到,
firstSubclass
开始为nil
,打印了QLDog
地址后,firstSubclass
才有值,为什么会这样呢?因为这是一个
懒加载
的过程,在用到的时候才有值
属性的赋值
此处我们通过clang
来探索属性的修饰对属性赋值的影响。
上代码:
QLPerson.h
@interface QLPerson : NSObject{
NSString *fullName;
}
@property (nonatomic,copy) NSString *nickName;
@property (nonatomic,strong) NSString *strongNickName;
@property (nonatomic) NSString *noaNickName;
@property (atomic) NSString *aNickName;
@property (nonatomic,assign) NSInteger age;
@property (nonatomic) NSInteger noaAge;
@property (atomic) NSInteger aAge;
@end
通过clang
将QLPerson.m
编译成QLPerson.cpp
,请参考我之前这篇文章OC代码转C/CPP代码
xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc QLPerson.m -o QLPerson.cpp
得到的QLPerson.cpp
拖入工程,不参与编译。在搜索框输入QLPerson_IMPL
得到
1、声明的属性,都被被注释,取而代之的是,将属性转成了成员变量
+getter setter 方法
。
2、原成员变量fullName
不变
3、方法test1 test2
变成了_I_QLPerson_test1(QLPerson * self, SEL _cmd)
,括号内参数即可看出OC的方法调用会默认传id self,SEL _cmd
两个参数。
property的getter setter方法
由上图,我们可以看到所有属性的getter和setter
方法,有些不一样,代码看起来有些乱,我将多余的类型强转去掉后,简化后代码如下:
1、属性通过getter方法得到数据,方法内通过
对象地址+偏移量
指向的内存得到。2、属性的赋值分两种:①
setProperty()
、②对象地址+偏移量
。3、对比
QLPerson.h
中的属性声明,nickName
的赋值是setProperty()
,其余均为self + 偏移量
。因为nickName用了copy修饰
。相关证明及其setter方法重定向到setproperty()的过程
,请到LLVM源码中查看。最终在CGObjC.cpp
的第858行得到
image.png
总结
setProperty()
在objc
中的运行过程,以后有空再补充。
网友评论