ios 全面解析block

憶江南的部落格發表於2015-10-13
typedef int(^MyBlock)();

void cFun(void(^blockName1)(), MyBlock blockName2){
//兩種寫法都可以
}

-(void)ocFun:(void(^)())blockName1 andOtherBlock:(MyBlock)blockName2{ 
 //注意第一種寫法的特別之處, OC函式要求變數型別和形參名分開, 所以寫法和C不同
}

在oc中呼叫cFun,直接cFun就可以了,但是ocFun就需要 [self ocFun].

block是一個特殊的OC物件, 它建立在棧上, 而不是堆上, 這麼做一個是為效能考慮,還有就是方便訪問區域性變數.

預設情況下block使用到的區域性變數都會被保留,而不是複製.

所以它無法改變區域性變數的值.

如果在變數面前加上__block, 那就是告訴編譯器, 當吧快從棧移動到堆上的時候,要把變數也複製一份放到堆上, 這樣我們就可以改變變數.

另外塊是在棧上分配的, 所以一旦離開作用域, 就會釋放, 因此如果你要把快用在別的地方, 必須要複製一份.

所以在屬性定義一個快的時候需要使用copy:  @property (nonatomic, copy) void (^onTextEntered)(NSString *enteredText);

塊是不能保留的, retain對塊沒有意義

ARC下Block何時會從棧自動被複制到堆, 以及__block和__weak的使用問題

由於Block是預設建立在棧上, 所以如果離開方法作用域, Block就會被丟棄, 在非ARC情況下, 我們要返回一個Block ,需要 [Block copy];

在ARC下, 以下幾種情況, Block會自動被從棧複製到堆:

1.被執行copy方法
2.作為方法返回值
3.將Block賦值給附有__strong修飾符的id型別的類或者Blcok型別成員變數時
4.在方法名中含有usingBlock的Cocoa框架方法或者GDC的API中傳遞的時候.

對於非ARC下, 為了防止迴圈引用, 我們使用__block來修飾在Block中實用的物件:

__block id blockSelf=self;

self.block=^{
NSLog(@"%@",blockSelf);  //在非ARC下對於棧上的_block物件, Block不會對其複製, 僅僅使用, 不會增加引用計數.
};

對於ARC下, 為了防止迴圈引用, 我們使用__weak來修飾在Block中實用的物件:

__weak id weakSelf=self;

self.block=^{
NSLog(@"%@",weakSelf);
};

如果要在ARC下, 為了防止迴圈引用, 使用__block來修飾在Block中實用的物件,仍然會被retain, 所以需要多做一些設定
__block id blockSelf=self;

self.block=^{
NSLog(@"%@",blockSelf);
blockSelf=nil;
};

並且一定要執行一次block();

這樣就使block斷開了與blockSelf的持有關係, 這是使用__block是為了允許在block修改其值.

相關文章