一暴构、產(chǎn)生原因
網(wǎng)上大部分帖子都表述為:"block里面引用了self導致循環(huán)引用"常遂,會讓大家理解為要顯式地出現(xiàn)"self"就會引起循環(huán)引用找田。其實這種說法是很不嚴謹?shù)摹?/p>
下面用代碼來說明:
*1 聲明幾個block和一個屬性:
@interface ViewController (){
void(^myBlock1)(void);
void(^myBlock2)(void);
void(^myBlock3)(void);
}
@property (nonatomic,copy) NSString *person;
@end
*2 使用weakSelf 不會 引起循環(huán)引用(以下是最常用但是不提倡方法毒姨,后面會提到原因冤竹,繼續(xù)看下去哦):
__weak typeof(self) weakSelf = self;
NSLog(@"init--> value:%@,address=%p,self=%p",self.person,self.person,self);
myBlock1 = ^(void){
//這樣不會造成循環(huán)引用
NSLog(@"execute1--> value:%@,address=%p,weakSelf=%p",weakSelf.person,weakSelf.person,weakSelf);
};
*3 直接使用self,會循環(huán)引用:Xcode會給警告
myBlock2 = ^(void){
//這樣造成循環(huán)引用
NSLog(@"execute2--> value:%@,address=%p,self=%p",self.person,self.person,self);
};
*4 要執(zhí)行的方法抽取出來案铺,也不會循環(huán)引用:
myBlock3 = ^(void){
//這樣也不會造成循環(huán)引用,已經(jīng)抽取出要執(zhí)行的方法
[weakSelf myBlock3Func];
};
- (void)myBlock3Func{
NSLog(@"execute3--> value:%@,address=%p,self=%p",self.person,self.person,self);
}
*5 block不是self的屬性或者變量時蔬芥,在block內(nèi)使用self也不會循環(huán)引用:
//block不是self的屬性時,block內(nèi)部使用self也不是循環(huán)引用
Animal *animal = [[Animal alloc] init];
animal.animalBlock = ^(void){
NSLog(@"animal--> value:%@,address=%p,self=%p",self.person,self.person,self);
};
所以說并不是在block中使用self必定會循環(huán)引用红且,要分情況處理坝茎,如果產(chǎn)生了循環(huán)引用如何解決呢:
二涤姊、解決循環(huán)引用
*1 為了方便使用暇番,首先定義兩個宏
#ifndef weakify
#define weakify(o) __typeof__(o) __weak o##__weak_ = o;
#define strongify(o) __typeof__(o##__weak_) __strong o = o##__weak_;
#endif
*2 使用如下代碼解決循環(huán)引用
weakify(self);
success:^(AFHTTPRequestOperation *operation, id responseObject) {
strongify(self);
if (!self__weak_) return ;
//...................
}
3* 總結解釋上述代碼作用
- weakify(self); 創(chuàng)建一個指向self的弱引用
- strongify(self); 當加上修飾符strong時,當別處把“self”釋放掉思喊,但調(diào)用該“self”的block如果仍然沒有執(zhí)行結束壁酬,那么系統(tǒng)就會等待block執(zhí)行完成后再釋放,對該“self”在block中的使用起到了保護作用。當block執(zhí)行結束后會自動釋放掉舆乔。
- if (!self__weak_) return ; ** 進行判斷岳服,如果在執(zhí)行strongify(self)之前“self已經(jīng)被釋放掉了,則此時self=nil希俩,所以直接return即可”**
三吊宋、 代碼驗證
*1 我們自定義一個類Text,在該類dealloc方法中加一行打印;
-(void)dealloc{
NSLog(@"dealloc %@被銷毀了Q瘴洹A选!A凵稀U馕恰!",[self class]);
}
*2 將Text作為另外一個類的屬性
@property(nonatomic,strong)Text *text;
*3 測試結果
Text *text=[[Text alloc]init];
self.text=text;
weakify(_text);
//開啟子線程
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{
NSInteger count =0;
strongify(_text);
while( count<10) {
count++;
NSLog(@"---------%@---%ld",_text__weak_,(long)count);
sleep(1);
}
});
//3秒后將 text對象 銷毀
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3*NSEC_PER_SEC)),dispatch_get_main_queue(), ^{
self.text=nil;
});
4* 第一次篙议,不使用 strongify(_text);
屏幕快照 2016-04-21 下午9.46.30.png
5*第二次唾糯,使用 strongify(_text);
屏幕快照 2016-04-21 下午9.46.05.png
可以清楚的看到,添加了strongify(_text)鬼贱,系統(tǒng)就會等待block執(zhí)行完成后再釋放text對象移怯,該text對象在block中的使用起到了保護作用。當block執(zhí)行結束后會自動釋放掉