一、Block的簡單介紹
Block 就是匿名函數 它是封裝了一個代碼塊,這個代碼塊在什么時候都可以執行;
使用Block的步驟就三步:1.定義Block變量;2創建Block的代碼塊 3.調用Block
(1)無參無返回值
void (^one) = ^{ NSLog(@"hello world!"); };?? 調用 one();
? (2)? 無參有返回值
int (^tow) = ^{ return 1; };? 調用? int a = tow();
? (3)? 有參無返回值
void (^three)(int) = ^(int a){ NSLog(@"hello world!"); };? 調用? int b = 2;? three(b);
? (4)? 有參有返回值
int (^four)(int,int) = ^(int a,int b){ return a + b;); };? 調用 int a = 1; int b = 2;?
int sum = four (a , b);
定義Block的另一種方式 一般用 typedef void (^BlockName)( );
二、Block的注意事項
typedef void (^BlockName)( );
1.調用Block的時候首先要判空 if (self.BlockName){ 在這里調用Block:self.BlockName( ) };
2.Block可以訪問局部變量,但是不能修改它的值;如果要修改的話該變量必須用__block修飾;
int a = 10; void(^BlockName)() = ^{? a++;? }; 此處a的值不能修改
原因:此處不能修改的原因是在編譯期間確定的,編譯器編譯的時候把a的值復制到block作為一個新變量(假設是a‘ = 10),此時a'和a是沒有關系的
3.如果block塊里邊有self這樣的代碼, self必須用__weak 修飾;
__self ViewController *controller = self;
void(^BlockName)() = ^{? NSLog(@"%@", controller.string); };
原因:block會對內部的對象進行一次retain,也就是說self會被retain一次。當self釋放的時候,需要block釋放后才會對self進行釋放,但是block的釋放又需要等self的dealloc中才會釋放。如此一來變形成了循環引用,導致內存泄露。(一句話防止循環引用)
4.在申明block屬性的時候用copy 后者strong修飾;
因為默認情況下,block是存檔在棧中,可能被隨時回收,需要copy到堆區一份,防止被釋放掉;
@property(copy,nonatomic)BlockName? myBlock;
5、在多線程環境下(block中的weakSelf有可能被析構的情況下),需要先將self轉為strong指針,避免在運行到某個關鍵步驟時self對象被析構。
__weak __typeof(self)weakSelf =self;
AFNetworkReachabilityStatusBlock callback= ^(AFNetworkReachabilityStatus status) {
__strong __typeof(weakSelf)strongSelf=weakSelf;
strongSelf.networkReachabilityStatus=status;if(strongSelf.networkReachabilityStatusBlock) {
strongSelf.networkReachabilityStatusBlock(status);
}
};
第四、五、六行,如果不轉成strongSelf而使用weakSelf,后面幾句話中,有可能在第四句執行之后self的對象可能被析構掉,然后后面的StausBlock沒有執行,導致邏輯錯誤。
這里邊的typeof(self) 指的是任意類型 ,還有一點 析構這個詞的解釋
需要注意的情況暫時能想到這么多!如還有其他請留言告訴我不甚感激!
三、Block的使用
Block的使用我就簡單說幾點應用場景,第一點 他可以傳遞參數,具體來說就是實現兩個ViewController之間值的傳遞;
第二點 他可以代替代理來使用;
第三點 他可以作為變量來傳值,一般在網絡請求的時候用的比較多;
四、Block的底層實現 因為它涉及到了數據結構方面的知識,我暫時看不懂;