block 顧名思義就是代碼塊,將同一邏輯的代碼放在一個塊,使代碼更簡潔緊湊,易于閱讀,而且它比函數(shù)使用更方便,代碼更美觀,因而廣受開發(fā)者歡迎。但同時 block 也是 iOS 開發(fā)中坑最多的地方之一,因此有必要了解下 block 的實現(xiàn)原理,知其然,更知其所以然,才能從根本上避免挖坑和踩坑。
需要知道的是,block 只是 Objective-C 對閉包的實現(xiàn),并不是 iOS 獨有的概念,在 C++、Java 等語言也有實現(xiàn)閉包,名稱不同而已。
Block屬性的聲明,首先需要用copy修飾符,因為只有copy后的Block才會在堆中,棧中的Block的生命周期是和棧綁定的
Block的定義格式
返回值類型(^block變量名)(形參列表) = ^(形參列表) {
};
調(diào)用Block保存的代碼
block變量名(實參);
typedefvoid(^BlockType)(int);
//聲明屬性
@property (copy) BlockType myBlock;
@property (nonatomic, copy)? void(^textBlock) (NSString*text); // 字符串回調(diào)
@property (nonatomic,copy)dispatch_block_t blockAction; // 點擊事件回調(diào)
回調(diào)值
__weaktypeof(self) weakSelf =self;
vc.v= ^(NSString*str){
weakSelf.textStr=str;
};
//有了atomic來保證基本的原子性還是沒有達(dá)到線程安全的,調(diào)用時需要把Block先賦值給本地變量,以防止Block突然改變。即便是先判斷了Block屬性不為空,在調(diào)用之前,一旦另一個線程把Block屬性設(shè)空了,程序就會crash:
if(self.myBlock)
{
self.myBlock(123);
}
//先判斷其是否為空,self.myBlock可能被另一個線程改為空,造成crash
//注意:atomic只會確保myBlock的原子性,這種操作本身還是非線程安全的
注:循環(huán)引用問題
在ARC下,由于__block抓取的變量一樣會被Block retain,所以必須用弱引用才可以解決循環(huán)引用問題
__weaktypeof(self) weakSelf =self;
self.myBlock= ^()
{
};