1、循环引用的时候用__weak与__strong是常见的手段
strong 修饰的属性会在赋值时调用被指向对象的 retain 方法,导致其引用计数加1 。
weak 则不会。
__weak typeof(self) weakSelf = self;
self.block = ^{
[weakSelf print];
}
上述方法可以解决循环引用的问题,但是当对象先与block释放的时候,block也就会被释放,这样的话self就指向了nil。等block回来时,其实在向一个nil发消息。
__weak typeof(self) weakSelf = self;
self.block = ^{
__strong typeof(weakSelf) strongSelf = weakSelf;
[strongSelf print];
};
__strong在block的内部临时把引用计数+1了,strongSelf是block内部的一个局部变量,变量的作用域仅限于局部代码,而程序一旦跳出作用域,strongSelf就会被释放,这个临时产生的“循环引用”就会被自动打破。
2、__unsafe__unretained
__unsafe_unretained:和__weak 一样,唯一的区别便是,对象即使被销毁,指针也不会自动置空, 此时指针指向的是一个无用的野地址。如果使用此指针,程序会抛出 BAD_ACCESS 的异常。
id __unsafe_unretained obj = [[NSMutableArray alloc]init];
[obj addObject:@"obj"];
这里先不管编译器的警告,继续执行,在第二条语句就会崩溃,分析:
附有__unsafe_unretained修饰符的变量同附有__weak修饰符的变量一样,因为自己生成并持有的对象不能继续为自己持有,所以生成的对象会立即被释放。也就是说在执行完init方法以后,obj指针所指向的内存就已经释放掉了,可是obj指针并没有像附加__weak的指针那样,将指针自动置为nil,它依然指向原来的地址,可是这块地址的内存已经被系统回收了,再访问就是非法的,也就是野指针,再执行后面的addObject方法自然会出错了。
也就是说上面的代码,把__unsafe_unretained换成__weak就不会崩溃,因为obj会自动制置为nil。对nil发送消息是不会有问题的。
https://blog.csdn.net/chenyong05314/article/details/55657388 这里形象的对比了strong、weak、__unsafe__unretained的内存区别。
3、____autoreleasing
id __strong obj0;
id __weak obj1;
id __autoreleasing obj2;
// __strong,__weak,__autoreleasing可以保证附有这些修饰符的自动变量初始化为nil
// 上面源码和下面效果等同
id __strong obj0 = nil;
id __weak obj1 = nil;
id __autoreleasing obj2 = nil;
//在文件中引入以下声明即可使用这两个函数
extern void _objc_autoreleasePoolPrint();//打印注册到自动释放池中的对象
extern uintptr_t _objc_rootRetainCount(id obj);//获取对象的引用计数
https://blog.csdn.net/junjun150013652/article/details/53149145这篇文章里面做了详细的解释,但是我还是不太明白,留着等后面在理解
看的有点晕,但是我理解就是把用__autoreleasing修饰,就是把变量放到@autoreleasepool中,把引用计数-1
网友评论