引言
上篇文章,通过lldb调试,找到了类的属性、成员变量、实例方法和类方法的存放位置。本文将讲述属性的补充内容。
###firstSubclass
上次我们在lldb调试过程中,发现这个firstSubclass都是为nil的情况,接下来,我们将讲述为什么。
上代码(QLDog继承于QLPerson):

  1. @interface QLDog : QLPerson
  2. @end
  3. main.m文件
  4. int main(int argc, const char * argv[]) {
  5. @autoreleasepool {
  6. QLPerson *person = [QLPerson alloc];
  7. NSLog(@"%@",person);
  8. }
  9. return 0;
  10. }

操作过程如下:007--iOS底层 - 类的结构(属性的赋值取值) - 图1
根据上图操作流程,我们可以看到,firstSubclass开始为nil,打印了QLDog地址后,firstSubclass才有值,为什么会这样呢?
因为这是一个**懒加载**的过程,在用到的时候才有值
###属性的赋值
此处我们通过clang来探索属性的修饰对属性赋值的影响。
上代码:
QLPerson.h

  1. @interface QLPerson : NSObject{
  2. NSString *fullName;
  3. }
  4. @property (nonatomic,copy) NSString *nickName;
  5. @property (nonatomic,strong) NSString *strongNickName;
  6. @property (nonatomic) NSString *noaNickName;
  7. @property (atomic) NSString *aNickName;
  8. @property (nonatomic,assign) NSInteger age;
  9. @property (nonatomic) NSInteger noaAge;
  10. @property (atomic) NSInteger aAge;
  11. @end

通过clangQLPerson.m编译成QLPerson.cpp,请参考我之前这篇文章OC代码转C/CPP代码

  1. xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc QLPerson.m -o QLPerson.cpp

得到的QLPerson.cpp拖入工程,不参与编译。在搜索框输入QLPerson_IMPL得到007--iOS底层 - 类的结构(属性的赋值取值) - 图2007--iOS底层 - 类的结构(属性的赋值取值) - 图3

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方法,有些不一样,代码看起来有些乱,我将多余的类型强转去掉后,简化后代码如下:007--iOS底层 - 类的结构(属性的赋值取值) - 图4
1、属性通过getter方法得到数据,方法内通过对象地址+偏移量指向的内存得到。
2、属性的赋值分两种:①setProperty()、②对象地址+偏移量
3、对比QLPerson.h中的属性声明,nickName的赋值是setProperty(),其余均为self + 偏移量。因为nickName用了copy修饰。相关证明及其setter方法重定向到setproperty()的过程,请到LLVM源码中查看。最终在CGObjC.cpp的第858行得到007--iOS底层 - 类的结构(属性的赋值取值) - 图5
###总结
setProperty()objc中的运行过程,以后有空再补充。