1、Blocks簡介
Block字面意思就是代碼塊 iOS4.0、Mac OS X 10.6開始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結合使用 爽爆了
使用:UIView動畫、PResentViewController、ASI
3、聲明和創建Block
聲明Block引用 無參無返回 無參有返回 有參無返回 有參有返回
定義Block
使用Block
typedef聲明 簡稱typedef 為現有類型創建一個新的名字,或稱為類型別名,在結構體定義,還有一些數組等地方都會用到
返回值或參數為Block的
snippet 代碼片段
4、Block對變量存取管理
1)局部變量
局部變量,在Block中只讀。Block定義時copy變量的值,在Block中作為常量使用,所以即使變量的值在Block外改變,也不影響它在Block中的值
2)__Block修飾的變量
如果要在block內修改block外聲明的局部變量,那么一定要對該變量加__block標記
3)Static修飾符的或全局變量
因為全局變量或靜態變量在內存中的地址是固定的,Block在讀取該變量值的時候是直接從其所在內存讀出,獲取到的是最新值,而不是在定義時copy的常量.
Block變量,被__Block修飾的變量稱作Block變量。 基本類型的Block變量等效于全局變量或靜態變量 但對象的block變量不會
5、Block的內存管理
非ARC下
Block是默認建立在棧上, 所以如果離開方法作用域, Block就會被丟棄
Block的copy、retain、release操作 不同于NSObject的copy、retain、release操作:
只要實現一個對周圍變量沒有引用的Block,就會顯示為是NSGlobalBlock
如果其中加入了對局部變量的引用,就是NSStackBlock
如果你對一個NSStackBlock對象使用了Block_copy()或者發送了copy消息,就會得到NSMallocBlock
1)NSGlobalBlock:retain、copy、release操作都無效;
2)NSStackBlock:retain、release操作無效,必須注意的是,NSStackBlock在函數返回后,Block內存將被回收,即使retain也沒用。
容易犯的錯誤是[mutableAarry addObject:stackBlock],(補:在ARC中不用擔心此問題,因為ARC中會默認將實例化的Block拷貝到堆上)在函數出棧后,從mutableAarry中取到的stackBlock已經被回收,變成了野指針。
正確的做法是先將[stackBlock copy]到堆上,然后加入數組:[mutableAarry addObject:[[stackBlock copy] autorelease]]。支持copy,copy之后生成新的NSMallocBlock類型對象。
3)NSMallocBlock支持retain、release,雖然retainCount始終是1,但內存管理器中仍然會增加、減少計數。copy之后不會生成新的對象,只是增加了一次引用,類似retain;
4)Block_copy與copy等效,Block_release與release等效;
5)對Block不管是retain、copy、release都不會改變引用計數retainCount,retainCount始終是1;
6)盡量不要對Block使用retain操作,不方便管理。
Block的使用:UIView動畫、presentViewController、ASI
6、Block對objc對象的內存管理
staticObj、globalObj、instanceObj、localObj、blockObj多種類型obj對象
主要是block被copy時其塊中用到的變量的引用計數
1)非ARC
globalObj和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下, 以下幾種情況, Block會自動被從棧復制到堆:
1.被執行copy方法
2.作為方法返回值
3.將Block賦值給附有__strong修飾符的id類型的類或者Blcok類型成員變量時
4.在方法名中含有usingBlock的Cocoa框架方法或者GDC的API中傳遞的時候.
Block中的對象的內存管理
ARC下
只有在使用local變量時,block會復制指針,且強引用指針指向的對象一次。其它如全局變量、static變量、block變量等,block不會拷貝指針,只會強引用指針指向的對象一次。
block的循環引用,因為block在拷貝到堆上的時候,會retain其引用的外部變量,那么如果block中如果引用了它的宿主對象,那很有可能引起循環引用。如:self.myblock = ^{[self doSomething];};
使用__weak避免循環引用
Tips:
內存主要分為
1.棧 - 由編譯器自動分配釋放 里面的變量通常是局部變量 函數參數等
2.堆 - 一般由程序員分配釋放,若程序員不釋放,程序結束時可能由OS回收 alloc
3.全局區(靜態區 static),全局變量和靜態變量的存儲是放在一塊的,初始化的全局變量和靜態變量在一塊區域,未初始化的全局變量和未初始化的靜態變量在相鄰的另一塊區域。- 程序結束釋放 static
People *p; People *p2 = nil;
4.另外還有一個專門放常量的地方。- 程序結束釋放 NSString *lastName = @“xue”;
lastName = @“dkjs”;
5、方法區
新聞熱點
疑難解答