iOS開發——高級篇——iOS中為什么block用copy屬性


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];


免責聲明!

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



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