[iOS]block詳解

1、block簡介

block字面意思就是代碼塊

iOS4.0 Apple引入的特性

block是Objective C語言中的對象 但是與NSObject有所區別 block是特殊的Objective C對象

block 對象提供了一個使用 C 語言和 C 派生語言(如 Objective-C 和 C++)來創建表達式作為一個特別的函數。在其他語言和環境中,一個block對象有時候被稱為“閉包(closure)”。在這里,它們通常被口語化為”塊(blocks)”,除非在某些范圍它們容易和標準 C 表達式的塊代碼混淆。

對于閉包(closure),有很多定義,其中閉包就是能夠讀取其它函數內部變量的函數

(以上內容了解)

“^”符號可以稱為caret['k?r?t]也叫脫字符 插入符

返回值(^塊對象名稱)(參數列表類型) = ^(參數列表){塊對象中的代碼};

2、用處

1)簡單的回調過程,不用再實現并調用某個函數 (UIView動畫)

2)代碼簡潔,減少冗余代碼

3)與GCD結合使用 爽爆了

3、block的聲明、使用

聲明block

block實現

調用block(代碼的執行順序)

typedef聲明 簡稱typedef 為現有類型創建一個新的名字,或稱為類型別名,在結構體定義,還有一些數組等地方都會用到

block作為屬性 使用copy

方法參數為block

(簡單了解)返回值為block 返回值block的類型要typedef

4、系統方法使用block 以及 系統方法內部的實現、實現兩個自定義類

動畫、present

blockButton

block和代理

snippet 代碼片段

5、block中變量存取管理

1)Static修飾符的或全局變量

因為全局變量或靜態變量在內存中的地址是固定的,block在讀取該變量值的時候是直接從其所在內存讀出,獲取到的是最新值,而不是在定義代碼塊時copy的常量.

2)局部變量

局部變量 在block中只讀, block定義時copy變量的值,在block中作為常量使用,所以即使變量的值在block外改變,也不影響它在block中的值

3)__block修飾的變量

如果要在block內修改block外聲明的局部變量,那么一定要對該變量加__block標記

block變量,被__block修飾的變量稱作block變量

6、block自身的內存管理

block是默認建立在棧上, 所以如果離開方法作用域, block就會被丟棄

非ARC下

只要實現一個對周圍變量沒有引用的block,就會顯示為是NSGlobalblock

如果其中加入了對周圍變量的引用,就是NSStackblock

如果你對一個NSStackblock對象使用了block_copy()或者發送了copy消息,就會得到NSMallocblock

1)NSGlobalblock:retain、copy、release操作都無效;

2)NSStackblock:retain、release操作無效,必須注意的是,NSStackblock在函數返回后,block內存將被回收。即使retain也沒用。容易犯的錯誤是[mutableAarry addObject:stackblock],在函數出棧后,從mutableAarry中取到的stackblock已經被回收,變成了野指針。正確的做法是先將[stackblock copy]到堆上,然后加入數組:[mutableAarry addObject:[[stackblock copy]]。支持copy,copy之后生成新的NSMallocblock類型對象。(補:在ARC中不用擔心此問題,因為ARC中會默認將實例化的block拷貝到堆上)

3)NSMallocblock支持retain、release,雖然打印的retainCount始終是1,但內存管理器中仍然會增加、減少計數。copy之后不會生成新的對象,只是增加了一次引用,類似retain;

block的copy、retain、release操作不同于NSObject的copy、retain、release操作:

4)block_copy與copy等效,block_release與release等效;

5)對block不管是retain、copy、release都不會改變引用計數retainCount,retainCount始終是1;

6)盡量不要對block使用retain操作,不方便管理。

7、block對block中使用的obj對象的內存管理

staticObj、instanceObj、localObj、blockObj多種類型obj對象

主要是block被copy時其塊中用到的變量的引用計數

1)非ARC

staticObj在內存中的位置是確定的,所以block copy時引用計數不會改變。

instanceObj在block copy時并沒有直接讓instanceObj對象本身引用計數加1,但卻讓self引用計數加1。所以在block中可以直接讀寫instanceObj變量。

localObj在block copy時,系統自動增加其引用計數指針復制。

blockObj在block copy時引用計數也不會改變。

使用__block避免循環引用 __block 類 *對象 = self

void(^block)(void)= ^{

[blockSelf doSomething];

};

7、循環引用retain cycle

循環引用指兩個對象相互強引用了對方,即retain了對方,從而導致誰也釋放不了誰的內存泄露問題。如聲明一個delegate時一般用assign而不能用retain或strong,因為你一旦那么做了,很大可能引起循環引用

釋放second 在fist delloc中釋放 fist的delloc什么時候執行呢 fist引用計數為0時執行 然而現在即便是將fist從window.rootViewController上卸載下來 即釋放一次 卻發現second還保留著first的一次引用 到頭來還是要釋放second 形成了delegate版本的retain cycle 即循環引用

釋放_pblock 在viewController delloc中釋放 delloc什么時候執行呢 viewController引用計數為0時執行 然而現在即便是將viewController從window.rootViewController上卸載下來 即釋放一次 卻發現_pblock還保留著viewController的一次引用 到頭來還是要釋放_pblock 形成了block版本的retain cycle 即循環引用

block在ARC下的內存管理

ARC下

在ARC下, 以下幾種情況, block會自動被從棧復制到堆:

1.被執行copy方法

2.作為方法返回值

3.將block賦值給附有__strong修飾符的id類型的類或者Blcok類型成員變量時

4.在方法名中含有usingblock的Cocoa框架方法或者GCD的API中傳遞的時候.

block中的對象的內存管理

ARC下

只有在使用local變量時,block會復制指針,且強引用指針指向的對象一次。其它如全局變量、static變量、block變量等,block不會拷貝指針,只會強引用指針指向的對象一次。

block的循環引用,因為block在拷貝到堆上的時候,會retain其引用的外部變量,那么如果block中如果引用了它的宿主對象,那很有可能引起循環引用。如:self.myblock = ^{[selfdoSomething];};

使用__weak避免循環引用

__weak typeof(ViewController *) weakSelf = self

self.myblock = ^{[weakSelfdoSomething];}

Tips:

內存主要分為

1、棧區(stack)— 由編譯器自動分配釋放,存放函數的參數值,局部變量的值等。

2、堆區(heap) — 一般由程序員分配釋放, 若程序員不釋放,程序結束時可能由OS回收。

3、全局區(靜態區)(static)—,全局變量和靜態變量的存儲是放在一塊的,初始化的全局變量和靜態變量在一塊區域,未初始化的全局變量和未初始化的靜態變量在相鄰的另一塊區域。程序結束后由系統釋放。

4、文字常量區 —常量字符串就是放在這里的。程序結束后由系統釋放。

5、程序代碼區—存放函數體的二進制代碼。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 內存管理 簡述OC中內存管理機制。與retain配對使用的方法是dealloc還是release,為什么?需要與a...
    丶逐漸閱讀 2,008評論 1 16
  • 1、概述 閉包 = 一個函數「或指向函數的指針」+ 該函數執行的外部的上下文變量「也就是自由變量」;Block 是...
    DeerRun閱讀 682評論 0 0
  • 《Objective-C高級編程》這本書就講了三個東西:自動引用計數、block、GCD,偏向于從原理上對這些內容...
    WeiHing閱讀 9,898評論 10 69
  • 多線程、特別是NSOperation 和 GCD 的內部原理。運行時機制的原理和運用場景。SDWebImage的原...
    LZM輪回閱讀 2,039評論 0 12
  • 一、Objective-C發展史 Objective-C從1983年誕生,已經走過了30多年的歷程。隨著時間的推移...
    沒事蹦蹦閱讀 5,903評論 12 34