Block 使用的小結 有轉的成分

2021-07-09 09:32:33 字數 4196 閱讀 5801

block 簡介

block 作為在 c語言的擴充套件,並不是高新技術,和其他語言的閉包或 lambda 表示式是一回事.需要注意的是由於 objective-c在 ios 中不支援 gc機制,使用 block 必須自己管理記憶體,而記憶體管理正是使用 bloc 坑最多的地方,錯誤的記憶體管理會導致 return cycle 記憶體洩露要麼記憶體被提前釋放了導致 crash.block 的使用很想函式指標,不過於函式最大的不同是:block 可以訪問函式意外.詞法作用域以內的外部變數的值.換句話說,block 不僅實現函式的功能,還能攜帶函式的執行環境.

可以這樣理解,block 其實包含兩個部分內容.

1.block 執行的**,這是在編譯的餓時候已經生成的;

2.乙個包含 block 執行是需要的所有外部變數值的資料結構.block 將使用到.作用於附近到的變數的值簡歷乙份快照拷貝到棧上.

block 與函式另乙個不同是,block 類似 obj 的隊形,可以使用自動釋放池管理記憶體(但 block 並不完全等於 obj 物件,後面詳細說明).

block 的型別與記憶體管理

根據 block 在記憶體中的位置分為三種型別

nsglobalblock,nsstackblock,nsmallockblobk.

nsglobalblock:類似函式 位於 text 段;

nsstackblock:位於棧記憶體,函式返回後 block 將無效;

nsmallocblock:位於堆記憶體;

一.nsglobalblock 如下,我們可以通過是否引用外部變數識別,未飲用外部變數即為 nsglobalblock,可以當做函式使用

int main(int argc, const

char * argv) ;

nslog(@"block is %@",sum);//列印結果 block is <__nsglobalblock__: 0x100001050>

return

0;}

nsstackblock如下

int main(int argc, const

char * argv) ;

nslog(@"block is %@",^);//列印結果 block is <__nsstackblock__: 0x7fff5fbff7d8>

//列印可看出 block 是乙個 nsstackblock,即在棧上,當函式返回時 block 將無效

nslog(@"block is %@",testblock);

//列印結果 block is <__nsmallocblock__: 0x100103b50>

//上面這句話在 非 arc 中列印是 nsstackblock. 但是在 arc中就是 nsmallocblock

//即在 arc 中缺省會將 block 從棧複製到堆上,而在非 arc 中需要手動 copy.

return

0;}

3.nsmallocblock 只需要對 nsstackblock 進行 copy 操作就可以獲取,但是 retain 操作不可以,會在下面說明 block 的 copy,retain,release 操作:

不同於 nsobjiect 的 copy,retain,release 操作:

block_copy 與 copy等效,block_release 於 release 等效:

對 block 不管是 retain,copy,release 操作都無效:

nsstackblock:retain,release操作無效,必須注意的是 ,nsstackblock在函式返回後,block 記憶體將被**.即使 retain 也沒用.容易犯的錯誤是[mutablearray addobject:stackblock],(在 arc 中不用擔心此問題)

nsmallocblock 支援 retain,release,雖然 retain count 始終是1,但記憶體管理器中仍然會增加,減少計數,copy 之後不會生成新的物件,只是增加了一次引用.類似 retain;

盡量不要對 block使用retain操作

block 對外部變數的訪問管理

基本資料型別

1.區域性布局

區域性自動變數,在 block 中唯讀.block 定義時 copy 變數的值.在 block 中作為常量使用,所以即使變數的值在 block 外改變,也不影響他在 block 中的值

int main(int argc, const

char * argv) ;

base=0;

printf("%ld\n",sum(1,2));

//這裡輸出的是103,而不是3,因為快內的 base 拷貝的常量100

return

0;}

2.static 修飾符修飾的全域性變數

以為全域性變數或者靜態變數在記憶體中的位址是固定的,block 在讀取該變數的時候是直接從其所在的呢村讀出的,獲取到的是最新值,而不是在定義時 copy 的常量,

int main(int argc, const

char * argv) ;

base=0;

printf("%ld\n",sum(1,2));

//這裡輸出的是4,而不是103,因為 base 被設定為0

printf("%d\n",base);

//這裡輸出1,在塊中被自加了

return

0;}

__block修飾的變數

block 變數,被__block 修飾的變數稱為 block 變數.基本型別的 block 變數等效於全域性變數,或靜態變數.block 被另乙個 block 使用時,另乙個 block 被 copy 到堆上時,被使用的 block 也會被 copy.但作為引數的 block 不會不會發生 copy

objc 物件

block 對於 objc 物件的記憶體管理較為複雜.這裡要分 static global local block 變數分析

迴圈引用 retain cycle

迴圈義勇是指兩個物件相互強引用了對方,即 retain 了對方,從而導致誰也釋放不了誰的記憶體洩露問題.如生命乙個 delegate 是一般用 assign 而不能用 retain 或 strong,因為一旦你那麼做了,很大可能一起迴圈引用.在以往的專案中,我幾次用動態記憶體檢查發現了迴圈引用導致記憶體洩露的問題

這裡將的是 block 得迴圈義勇問題,因為 block 在拷貝到堆上的時候,會 retain 起引用的外部變數,那麼如果 block 中如果引用了他的宿主物件,那麼很有可能引起迴圈引用

self

.myblock = ^;

//為測試迴圈引用,寫了些測試**用於避免迴圈引用的方法

- (void)dealloc

- (id)init

;#elif testcycleretaincase2

//會迴圈引用

__block testcycleretain *weakself = self;

self

.myblock = ^;

#elif testcycleretaincase3

//不會迴圈引用

__weak testcycleretain *weakself = self;

self

.myblock = ^;

#elif testcycleretaincase4

//不會迴圈引用

__unsafe_unretained testcycleretain *weakself = self;

self

.myblock = ^;

#endif

nslog(@"myblock is %@", self

.myblock);

}return

self;

}- (void)dosomething

int main(int argc, char *argv)

}

經過上面的測試發現,在加了__weak 和__unsafe_unretained的變數引入後,testcycleretain 方法可以正常執行 dealloc 方法,而不轉換和使用)__block 轉換的變數都會引起迴圈引用.

因此防止迴圈引用的方法就是

__unsafe_unretainedtestcuycleretain *weakself=self;

@end

Block的知識小結

磁碟分割槽格式化檔案系統後,會分為inode和block兩部分內容 1 磁碟讀取資料是按照block為單位讀取的 2 乙個檔案可能占用多個block。每讀取乙個block就會消耗一次磁碟i o 3 如果要提高磁碟io效能,那麼就應該盡可能一次性讀取資料盡量的多。4 乙個block只能存放乙個檔案的內...

Block的使用 初探Block

看了兩天的block。網上是有非常多解說與教程,也有講得非常好的。這裡就主要解說下我的理解與收穫。歡迎拍磚。所謂block。我覺得應該是乙個閉包函式。而閉包,就是說block以及內部全部的變數生命週期都在其呼叫函式的生命週期內。它一被呼叫完畢,則會被立刻釋放。這裡不講執行機制,僅僅簡要地講基本的用法...

Block語法的使用

block的作用 同 協議 通知一樣用於物件和物件之間的通訊。block的定義 是乙個匿名的函式 塊,此 塊可以作為引數傳遞給其他物件。block的應用場景 物件與物件之間的通訊。block的語法 block的宣告 第一種 int myblock int 第二種 typedef int mybloc...