block的使用和注意事項


1. Block的聲明和線程安全

Block屬性的聲明,首先需要用copy修飾符,因為只有copy后的Block才會在堆中,棧中的Block的生命周期是和棧綁定的,可以參考之前的文章(iOS: 非ARC下返回Block)。

另一個需要注意的問題是關於線程安全,在聲明Block屬性時需要確認“在調用Block時另一個線程有沒有可能去修改Block?”這個問題,如果確定不會有這種情況發生的話,那么Block屬性聲明可以用nonatomic。如果不肯定的話(通常情況是這樣的),那么你首先需要聲明Block屬性為atomic,也就是先保證變量的原子性(Objective-C並沒有強制規定指針讀寫的原子性,C#有)。

比如這樣一個Block類型:

typedef void (^MyBlockType)(int);

屬性聲明:

@property (copy) MyBlockType myBlock;

這里ARC和非ARC聲明都是一樣的,當然注意在非ARC下要release Block。

 

但是,有了atomic來保證基本的原子性還是沒有達到線程安全的,接着在調用時需要把Block先賦值給本地變量,以防止Block突然改變。因為如果不這樣的話,即便是先判斷了Block屬性不為空,在調用之前,一旦另一個線程把Block屬性設空了,程序就會crash,如下代碼:

if (self.myBlock)
{
//此時,走到這里,self.myBlock可能被另一個線程改為空,造成crash
//注意:atomic只會確保myBlock的原子性,這種操作本身還是非線程安全的
self.myBlock(123);
}

 

所以正確的代碼是(ARC):

MyBlockType block = self.myBlock;
//block現在是本地不可變的
if (block)
{
block(123);
}

在非ARC下則需要手動retain一下,否則如果屬性被置空,本地變量就成了野指針了,如下代碼:

//非ARC
MyBlockType block = [self.myBlock retain];
if (block)
{
block(123);
}
[block release];

 2.

2. 循環引用問題

循環引用是另一個使用Block時常見的問題。

在ARC下,由於__block抓取的變量一樣會被Block retain,所以必須用弱引用才可以解決循環引用問題,iOS 5之后可以直接使用__weak,之前則只能使用__unsafe_unretained了,__unsafe_unretained缺點是指針釋放后自己不會置空。示例代碼:

//iOS 5之前可以用__unsafe_unretained
//__unsafe_unretained typeof(self) weakSelf = self;
__weak typeof(self) weakSelf = self;
self.myBlock = ^(int paramInt)
{
//使用weakSelf訪問self成員
[weakSelf anotherFunc];
};

 

在非ARC下,顯然無法使用弱引用,這里就可以直接使用__block來修飾變量,它不會被Block所retain的,參考代碼:

//非ARC
__block typeof(self) weakSelf = self;
self.myBlock = ^(int paramInt)
{
//使用weakSelf訪問self成員
[weakSelf anotherFunc];
};

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM