Block的聲明和線程安全
Block屬性的聲明缴川,首先需要用copy修飾符茉稠,因為只有copy后的Block才會在堆中,棧中的Block的生命周期是和棧綁定的把夸。
另一個需要注意的問題是關于線程安全而线,在聲明Block屬性時需要確認“在調用Block時另一個線程有沒有可能去修改Block?”這個問題恋日,如果確定不會有這種情況發(fā)生的話膀篮,那么Block屬性聲明可以用nonatomic。如果不肯定的話(通常情況是這樣的)岂膳,那么你首先需要聲明Block屬性為atomic誓竿,也就是先保證變量的原子性(Objective-C并沒有強制規(guī)定指針讀寫的原子性,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現(xiàn)在是本地不可變的
if (block)
{
block(123);
}
在非ARC下則需要手動retain一下,否則如果屬性被置空秃症,本地變量就成了野指針了候址,如下代碼:
//非ARC
MyBlockType block = [self.myBlock retain];
if (block)
{
block(123);
}
[block release];