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...