iOS Block与循环引用
程序员文章站
2024-02-29 22:22:40
...
循环引用的产生:
下面以ARC 下为例
忧郁Block对象内部引用了外部的变量,而外部的变量又引用了当前的这个block,形成了彼此持有对方。如果外界不主动打断这种链接,那么就会一直持有,导致当前变量对象无法释放。
解决循环引用
1.使用__weak修饰
- (void)test {
__weak Person *weakPerson = self;
self.pblock = ^{
NSLog(@"------%d", weakPerson.age);
};
}
上述代码因为采用了__weak修饰,导致了Block对象内部以weak形式持有Person示例,用clang编译成cpp文件,查看如下
//xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc -fobjc-arc -fobjc-runtime=ios-9.0.0 Person.m
struct __Person__test_block_impl_0 {
struct __block_impl impl;
struct __Person__test_block_desc_0* Desc;
Person *__weak weakPerson; //weak指针
__Person__test_block_impl_0(void *fp, struct __Person__test_block_desc_0 *desc, Person *__weak _weakPerson, int flags=0) : weakPerson(_weakPerson) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
2.____unsafe_unretained修饰变量
也可以实现接触循环引用的问题,但是不常用,主要原因是因为____unsafe_unretained指向的对象销毁时,不会自动让这个指针指向的地址值不变,这样导致不安全,__weak指向的对象不存在,则会自动置为nil
- (void)test {
__unsafe_unretained Person *weakPerson = self;
self.pblock = ^{
NSLog(@"------%d", weakPerson.age);
};
}
3.__block解决循环引用问题
在block内部对当前 对象进行置nil,同时必要调用一次block()。
因为block内部使用__block修饰的当前对象,此时,block引用__block修饰的block对象成员,而此__block对象内部引用当前对象,此时三者形成互相持有关系。
当调用block()后,__block对象内部持有的指向当前对象的指针置nill,此时也就解除了批次的循环指针指向.
ARC下最好的实现,就是用__weak,当然如果在MRC下,也可以使用__block解决,因为MRC下__block对象不会对当前的变量进行retain操作