block深入淺出

elliotsomething發表於2016-04-30
typedef void (^Callback)(id result);
- (void)viewDidLoad {
[self callbackDosomething:^(id result) {
NSLog(@"%@",result);
}];

}

- (void)callbackDosomething:(Callback)callback{
callback = [self callbackReDosomething:callback];
}

- (Callback)callbackReDosomething:(Callback)callback{
if (callback) {
callback(@"dosomething");
}
return callback;
}
此處的callback就是用來傳遞的,在另一個方法裡面才callback回撥

block是OC對閉包實現的一個物件,為什麼說block是物件了,因為在block的資料結構中存在isa指標

1、block分為三種:NSConcreteGlobalBlock、NSConcreteStackBlock、NSConcreteMallocBlock。

第一種block是全域性block,如果一個block沒有引入外部變數,那麼這個block就是全域性block,全域性block在編譯時期就已經確定大小了,如同巨集一樣;
第二種block是棧block,當引入了外部變數時,這種block就是棧block了,NSConcreteStackBlock內部會有一個結構體__main_block_impl_0,這個結構體會儲存外部變數,使其體積變大。而這就導致了NSConcreteStackBlock並不像巨集一樣,而是一個動態的物件。而它由於沒有被持有,所以在它的內部,它也不會持有其外部引用的物件。(注意,棧block是不會持有外部變數的)
第三種block是堆block,堆block就是一個block被copy到堆上,堆block會持有外部引用物件,所以會導致可能的物件延遲釋放,或者迴圈引用的問題。(在MRC下,區域性變數如果沒有用_block,在block中會對其進行copy操作,而用了_block則只會引用其地址,這也就是為什麼改變區域性變數需要用_block修飾了)

注意:在MRC和ARC下block的區別
將block作為例項的屬性變數時,MRC下需要手動copy到堆中,也就是棧block–>堆block(如果不copy就是棧block,棧block不會持有物件),而在ARC中屬性賦值預設是strong,到了block自然就變成了copy,所以在ARC下預設是堆block。

block 的生命週期:
(特別注意:堆block會持有物件,這樣就導致,如果堆block不釋放的話,其持有的物件也不會釋放,這樣就會導致迴圈引用或者延遲釋放,所以一般的做法是_weak(ARC)或_block(MRC))

巨集:
·#define weak(obj) __weak typeof(obj) weak##obj = obj