《Objective-C高级编程 iOS与OS X多线程与内存管

2019-01-06  本文已影响7人  我才是臭吉吉

内存管理篇:8.ARC实现之__weak

我们知道,weak修饰的变量,其地址是被存储在一个专用的散列表中,此散列表的键值为原内存的散列值(即对象地址的hash值)。

weak表.jpg

__weak修饰的变量,其主要存在两大功能:

  1. 当其引用的对象被释放时,此变量自动被赋值为nil
  2. 使用__weak修饰的变量时,实际上使用的是添加到autoreleasePool中的对象

当__weak变量引用的对象被释放时,其自动被赋值为nil

先看示例:

{
    // obj为强引用变量且已经被赋值
    id __weak obj1 = obj;
}

编译后的模拟代码为:

id obj1;
objc_initWeak(&obj1, obj);
objc_destroyWeak(&obj1);

objc_initWeak方法,即为:

obj1 = 0;
objc_storeWeak(&obj1, obj);

objc_destroyWeak方法,即为:

objc_storeWeak(&obj1, 0);

由此可以看出,

  1. 对于初始化的weak变量:为变量赋值为0,并将其地址存储到weak表中,对象内存的散列值所在的地址中
  2. 释放weak变量时:则是在weak表中,将对象内存散列值所在地址存储的数据中,将存储的变量清空

由于可以使用多个weak变量指向同一对象,所以在weak表中,一个键值的散列地址中可以存储多个weak变量地址。

结论:
weak对象释放时,自动置为nil的原因

使用__weak修饰的变量时,实际上使用的是添加到autoreleasePool中的对象

还是先看实例:

{
    // obj为强引用变量,且已被赋值
    id __weak obj1 = obj;
    NSLog(@"%@", obj1);
}

编译后的模拟代码为:

// 初始化weak变量并赋值
id obj1;
objc_initWeak(&obj1, obj);
// ???
id tmp = objc_loadWeakRetained(&obj1);
// ???
objc_autorelease(tmp);
NSLog(@"%@", tmp);
// 释放weak变量
objc_destroyWeak(&obj1);

其中:

  1. 先通过objc_loadWeakRetained方法,将weak变量对应引用的对象取出,并进行retain操作。
  2. 使用objc_autorelease方法,将生成的临时对象加入到autoreleasePool中,即可保证对象的生存期,以便正常使用。

注意:

id __weak obj1 = obj;
id tmp = obj1;
NSLog(@"1.%@", tmp);
NSLog(@"2.%@", tmp);
NSLog(@"3.%@", tmp);
NSLog(@"4.%@", tmp);
NSLog(@"5.%@", tmp);
// 这样,autoreleasePool只会将obj1插入一次
上一篇 下一篇

猜你喜欢

热点阅读