ios中的循环引用
在ios中使用
block (闭包)
的时候,代码块中使用到self 有可能出现循环引用循环引用的两种形式:
- 多个对象循环强引用,都不能释放,导致内存泄露
- 单例强引用其他对象,由于单例不会被释放销毁,程序结束时才会销毁,导致其他对象不能及时销毁
OC中的循环引用
- 建立
NetworkTools
类
@interface NetworkTools ()
@property (nonatomic, strong) void(^finishedBlock)();
@end
@implementation NetworkTools
- (void)loadDataWithFinishBlock:(void (^)())finishBlock {
self.finishedBlock = finishBlock;
[self work];
}
- (void)work {
if (self.finishedBlock) {
self.finishedBlock();
}
}
- (void)dealloc {
NSLog(@"%@ dealloc",self);
}
@end
- 示例化
NetworkTools
并加载数据
@interface ViewController ()
@property (nonatomic, strong) NetworkTools *networkTools;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.networkTools = [NetworkTools new];
[self.networkTools loadDataWithFinishBlock:^(){
NSLog(@"%@",self.view);
}];
}
- (void)dealloc {
NSLog(@"%@ dealloc",self);
}
@end
运行测试会出现循环引用
- 原因:
- viewController ==> networkTools ==> finishedBlock ==> self(viewController)
- ==> 表示强引用
解除循环引用
使用
__weak typeof(self) weakSelf = self;
- 如果self 被释放,weakSelf 的地址将改为nil
- (void)viewDidLoad {
[super viewDidLoad];
self.networkTools = [NetworkTools new];
__weak typeof(self) weakSelf = self;
[self.networkTools loadDataWithFinishBlock:^(){
NSLog(@"%@",weakSelf.view);
}];
}
- 使用
__unsafe_unretained typeof(self) weakSelf = self;
- weakSelf 是assign,当self被释放时,weakSelf 的地址不会改变,可能会出现野指针错误
- (void)viewDidLoad {
[super viewDidLoad];
self.networkTools = [NetworkTools new];
__unsafe_unretained typeof(self) weakSelf = self;
[self.networkTools loadDataWithFinishBlock:^(){
NSLog(@"%@",weakSelf.view);
}];
}
- 推荐使用
__weak
的方式解决OC中的循环引用
swift 中的循环引用
- 建立
NetworkTools
类
class NetworkTools1: NSObject {
var finishedCallBack: (() -> ())?
func loadData(finishedCallBack: () -> ()) {
dispatch_async(dispatch_get_global_queue(0, 0)) { () -> Void in
print("加载数据")
NSThread.sleepForTimeInterval(2)
self.finishedCallBack = finishedCallBack;
self.work()
}
}
func work() {
finishedCallBack?()
}
deinit {
print("\(self) deinit")
}
}
- 示例化
NetworkTools
并加载数据
class ViewController1: UIViewController {
var networkTools: NetworkTools1?
override func viewDidLoad() {
super.viewDidLoad()
networkTools = NetworkTools1()
networkTools?.loadData({ () -> () in
print("\(self.view)")
})
}
deinit {
print("\(self) deinit")
}
}
运行测试会出现循环引用
- 原因:
- ViewController1 ==> networkTools ==> finishedCallBack ==> self(ViewController1)
解除循环引用
- 使用
weak
- 当self释放时,weakSelf为变为 nil
weak var weakSelf = self
networkTools?.loadData({ () -> () in
print("\(weakSelf?.view)")
})
- 使用
[weak self]
- 闭包中的self是可选项,当self 被释放时,
self?
不执行,更安全
- 闭包中的self是可选项,当self 被释放时,
networkTools?.loadData({[weak self] () -> () in
print("\(self?.view)")
})
- 使用
[unowned self]
- self 不是可选项,如果self 已经被释放,则会出现野指针错误
networkTools?.loadData({[unowned self] () -> () in
print("\(self.view)")
})
- swift 中推荐使用
[weak self]
解决循环引用