一、__block
優(yōu)點(diǎn):
- 擴(kuò)大變量的作用域苏研。</br>
- 控制對象的生命周期,防止循環(huán)引用摹蘑。
- 是強(qiáng)引用,在非ARC環(huán)境下可以使用 __block替代__weak</br>
<pre>
int a = 0;
self.theBlock = ^(){
a = 2;
};
報錯衅鹿,a的值不能被修改撒踪,因?yàn)檫@里只是簡單的值傳遞。
__block int a = 0;
self.theBlock = ^(){
a = 2;
};
編譯通過大渤,指針傳遞制妄。
下面來看看block的作用域,block有以下三種:
1._NSConcreteStackBlock 保存在棧中的block泵三,出棧時會被銷毀
2._NSConcreteGlobalBlock 全局的靜態(tài)block耕捞,不會訪問任何外部變量
3._NSConcreteMallocBlock 保存在堆中的block衔掸,當(dāng)引用計(jì)數(shù)為0時會被銷毀
一般我們接觸到得是在棧上生成的block。當(dāng)我們把Block作為全局變量使用時:
void (^block)(void) = ^{NSLog(@"This is a Global Block");};
int main(int argc, const char * argv[]) {
@autoreleasepool {
block();
}
return 0;
}
分配在全局變量上的Block,在變量作用域外也可以通過指針安全的訪問俺抽。</br>但分配在棧上的Block敞映,如果它所屬的變量作用域結(jié)束,該Block就被廢棄磷斧。
同樣地, __block變量也分配在棧上振愿,當(dāng)超過該變量的作用域時,該__block變量也會被廢棄瞳抓。
循環(huán)引用:我們可以使用下述代碼解除Block循環(huán)引用的問題
__block id tmp = self;
void(^block)(void) = ^{
tmp = nil;
};
block();
通過執(zhí)行block方法埃疫,nil被賦值到__block變量tmp中。這個時候__block變量對 self
的強(qiáng)引用失效孩哑,從而避免循環(huán)引用的問題栓霜。缺點(diǎn)是執(zhí)行block才能解除循環(huán)引用横蜒。
</pre>
我們一般可以使用copy方法手動將 Block 或者 block變量從棧復(fù)制到堆上胳蛮。
比如我們把Block做為類的屬性訪問時,我們一般把該屬性設(shè)為copy丛晌。
在MRC環(huán)境下仅炊,__block是弱引用,在ARC環(huán)境下是強(qiáng)引用澎蛛,親測抚垄,很奇怪
二、__weak
優(yōu)點(diǎn):
- 弱引用谋逻,防止循環(huán)引用
.h
@property (nonatomic, strong) People \*myPeople;
@property (nonatomic, strong) void(^theBlock)();
.m
self.theBlock = ^(){
self.myPeople.name = @"ddd";
};
當(dāng)出棧呆馁,之后controller的dealloc()方法未被調(diào)用
作如下修改
self.theBlock = ^(){
weakSelf.myPeople.name = @"ddd";
};
dealloc()被調(diào)用,在MRC環(huán)境下用retainCount方法也能看到引用計(jì)數(shù)的變化
總結(jié):
__weak本身可以防止循環(huán)引用毁兆,但是當(dāng)block外部的變量釋放之后浙滤,里面也會出現(xiàn)訪問不到對象的問題,這時候气堕,在block里面用__strong來修飾weakObj纺腊,就可以使外部對象既能保持住,又能防止循環(huán)引用茎芭。
參考文檔
__weak與__block區(qū)別
黑幕背后的__block修飾符
Objective-C中的Block
@3樓
在start()
方法結(jié)束后2秒揖膜,打印shop的string屬性,如下
**
2017-03-25 18:11:01.749 TestWeak[57495:1819695] shop --0x7fff507bbb58
2017-03-25 18:11:01.750 TestWeak[57495:1819695] weakShop --0x7fff507bbb50
2017-03-25 18:11:03.750 TestWeak[57495:1819695] (null)
**
shop已經(jīng)被釋放梅桩,string屬性沒能成功打印
- (void)viewDidLoad {
[super viewDidLoad];
[self start];
}
-(void)start{
RBShop *shop = [[RBShop alloc] init];
shop.string = @"welcome";
__weak typeof(shop) weakShop = shop;
shop.myBlock = ^(){
// RBShop *strongshop = weakShop;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"%@",weakShop.string);
// NSLog(@"strongshop -- %p",&strongshop);
});
};
shop.myBlock();
NSLog(@"shop --%p",&shop);
NSLog(@"weakShop --%p",&weakShop);
}```
將注釋打開
-(void)start{
RBShop *shop = [[RBShop alloc] init];
shop.string = @"welcome";
__weak typeof(shop) weakShop = shop;
shop.myBlock = ^(){
RBShop *strongshop = weakShop;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"%@",strongshop.string);
NSLog(@"strongshop -- %p",&strongshop);
});
};
shop.myBlock();
NSLog(@"shop --%p",&shop);
NSLog(@"weakShop --%p",&weakShop);
}
打印如下
**
2017-03-25 18:12:26.753 TestWeak[57516:1821278] shop --0x7fff5d856b58
2017-03-25 18:12:26.754 TestWeak[57516:1821278] weakShop --0x7fff5d856b50
2017-03-25 18:12:28.946 TestWeak[57516:1821278] welcome
2017-03-25 18:12:28.947 TestWeak[57516:1821278] strongshop -- 0x608000248f60
**
最后數(shù)據(jù)打印了出來次氨,shop也釋放了
針對**在block里面用__strong來修飾weakObj,就可以使外部對象既能保持住摘投,又能防止循環(huán)引用**這句話:
>在block里面再對weakshop進(jìn)行一次強(qiáng)引用煮寡,這里的生成的strongshop,不會干擾外部的對象犀呼,當(dāng)cgd內(nèi)部的block執(zhí)行結(jié)束就會釋放掉shop