iOS-底层原理 10:strong©&weak底层分析 以及 方法签名和attribute简写含义

clang编译的cpp文件中可以发现strong & copy & weak 修饰的属性在编译的底层代码中是有区别的。

修饰的属性strong & copy & weak 底层分析

  • LGPerson中我们定义了两个两个属性,分别用copystrong修饰
image
  • clangmain.m文件编译成main.cpp,然后发现copystrong修饰的属性的set方法是有区别的
image

这里就有疑问了,为什么copy修饰的属性使用了objc_setProperty,而strong修饰的没有

  • 在LLVM中搜索”objc_setProperty,找到如下所示的getOptimizedSetPropertyFn方法中
image

从这里即可看出,针对不同的修饰符,返回的那么是不同的
copy修饰

  • 如果是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源码中的如下方法

image

然后通过汇编调试发现,最终都会走到objc_storeStrong

  • copy修饰的属性汇编调试结果
image
  • strong修饰的属性汇编调试结果
image
  • 源码中搜索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方法,如下图所示,发现copystrong修饰的属性执行的策略是不一致的
image
  • llvm中搜索EmitARCStoreStrongCall方法,在GenerateCopyHelperFunction方法有调用,然后在这里发现了strong 和 weak的不同处理
image
其中BlockCaptureEntityKind有如下的枚举值以及表示的含义
image
  • 如果是weak修饰,执行EmitARCCopyWeak方法,如下所示,weak在底层的调用是 objc_initWeak
image
  • 如果是strong修饰,执行EmitARCStoreStrongCall方法

结论

综上分析可得如下几点:

1,copy修饰:

  • 如果是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

2, copystrongweak :

  • copystrong 在底层都调用objc_storeStrong,本质是新值retain,旧值release
  • copystrong修饰的属性在底层编译的不一致,主要还是llvm中对其进行了不同的处理的结果。copy的赋值是通过objc_setProperty,而strong是执行EmitARCStoreStrongCall方法,赋值时通过self + 内存平移(即将指针通过平移移至name所在的位置,然后赋值),然后还原成 strong类型
  • weak 执行EmitARCCopyWeak方法,在底层调用objc_initWeak

weak修饰的对象释放则自动被置为nil的实现原理:

weak 关键字的作用弱引用,所引用对象的计数器不会加一,并在引用对象被释放的时候自动被设置为 nil。

weak的函数调用关系图过程:

image.png

Runtime维护了一个weak表(weak_table_t),存储指向某个对象的所有weak指针
weak表(weak_table_t)其实是一个hash(哈希)表,存储所有引用weak对象Key是所指对象的地址Valueweak指针的地址数组(这个地址的值是所指对象的地址,此地址是weak_entry_t 类型结构体)。

image.png

weak_table_t结构体如下:

struct  weak_table_t {
    weak_entry_t * weak_entries; //保存了所有指向指定对象的weak指针   weak_entries的对象
    size_t    num_entries;      // weak对象的存储空间
    uintptr_t mask;             //参与判断引用计数辅助量
    uintptr_t max_hash_displacement; //hash key 最大偏移值
};

weak 的实现原理可以概括一下三步:

  • 1、初始化时:runtime会调用objc_initWeak函数,初始化一个新的weak指针指向对象的地址。
  • 2、添加引用时:objc_initWeak函数会调用objc_storeWeak()函数objc_storeWeak() 的作用是更新指针指向,创建对应的弱引用表
  • 3、释放时,调用clearDeallocating函数clearDeallocating函数首先根据对象地址获取所有weak指针地址的数组,然后遍历这个数组把其中的数据设为nil,最后把这个entryweak表中删除,最后清理对象的记录

你可能感兴趣的:(iOS-底层原理 10:strong©&weak底层分析 以及 方法签名和attribute简写含义)