1.什么時候會發(fā)生循環(huán)引用
將一個提前準(zhǔn)備好的代碼塊, 在需要執(zhí)行的時候立即執(zhí)行, 在不需要立即執(zhí)行的時候, 用個屬性將這個函數(shù)傳遞過來的block記錄下來, 產(chǎn)生了強(qiáng)引用, 此時就會發(fā)生循環(huán)引用
2.怎么解決循環(huán)引用
那么怎么解決循環(huán)引用, 就是打破任一方的強(qiáng)引用
.
其中使用最多的就是__weak, 聲明一個弱引用類型的自己, 解除循環(huán)引用, 其中__weak跟weak類似, 當(dāng)對象被系統(tǒng)回收時, 它的內(nèi)存地址會自動指向nil, 對nil進(jìn)行任何操作不會有反應(yīng)
但其實(shí)在ios4的時候, 也可以使用__unsafe_unretained, 解除強(qiáng)引用, 但是它存在一定的不安全性, 原理和assign類似, 當(dāng)對象被系統(tǒng)回收時, 它的內(nèi)存地址不會自動指向nil, 就有可能出現(xiàn)壞內(nèi)存地址的訪問, 也就發(fā)生野指針錯誤
在之前發(fā)現(xiàn)了很多解除循環(huán)引用的時候, 會先使用__weak, 聲明自己為弱引用類型, 然后在準(zhǔn)備好的代碼塊中也就是block中, 再對弱引用對象利用__strong 做一次強(qiáng)操作 , 仔細(xì)驗(yàn)證發(fā)現(xiàn)再做強(qiáng)引用操作是冗余的, 并不會產(chǎn)生影響, 可以不用寫
3.如何驗(yàn)證是否發(fā)生循環(huán)引用
.
4.simple demo
#import "ViewController.h"
#import "NetworkTools.h"
@interface ViewController ()
@property (nonatomic, strong) NetworkTools *tools;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.tools = [[NetworkTools alloc] init];
/*
//解決方式三: __unsafe_unretained 不推薦, 不安全
__unsafe_unretained typeof(self) weakSelf = self;
[self.tools loadData:^(NSString *html) {
__strong typeof(self) strongSelf = weakSelf;
NSLog(@"%@%@",html,strongSelf.view);
strongSelf.view.backgroundColor = [UIColor redColor];
}];
*/
//解決方式二: __weak
__weak typeof(self) weakSelf = self;
[self.tools loadData:^(NSString *html) {
__strong typeof(self) strongSelf = weakSelf;
NSLog(@"%@%@",html,strongSelf.view);
strongSelf.view.backgroundColor = [UIColor redColor];
}];
}
//解決方式一:
- (void) method1{
NetworkTools *tools = [[NetworkTools alloc] init];
[tools loadData:^(NSString *html) {
NSLog(@"%@%@",html,self.view);
self.view.backgroundColor = [UIColor redColor];
}];
}
- (void)dealloc {
NSLog(@"VC dealloc");
}
@end
#import "NetworkTools.h"
@interface NetworkTools ()
//用一個屬性 來記錄 函數(shù)傳遞過來的 block
@property (nonatomic, copy) void(^finishedBlock)(NSString *);
@end
@implementation NetworkTools
- (void)loadData:(void (^)(NSString *))finishedCallBack {
//開始記錄blcok
self.finishedBlock = finishedCallBack;
dispatch_async(dispatch_get_global_queue(0, 0), ^{
[NSThread sleepForTimeInterval:3];
//開始耗時任務(wù)
NSLog(@"開始加載數(shù)據(jù)");
dispatch_async(dispatch_get_main_queue(), ^{
//調(diào)用方法
[self working];
});
});
}
- (void) working {
//執(zhí)行block
if (self.finishedBlock) {
self.finishedBlock(@"<html>");
}
}
- (void)dealloc {
NSLog(@"Tools dealloc");
}
@end