1、Blocks簡(jiǎn)介
Block字面意思就是代碼塊 iOS4.0、Mac OS X 10.6開始Apple引入的特性
Block是Objective C語言中的對(duì)象 但是與NSObject有所區(qū)別 Block是特殊的Objective C對(duì)象
Block 對(duì)象提供了一個(gè)使用 C 語言和 C 派生語言(如 Objective-C 和 C++)來創(chuàng)建表達(dá)式作為一個(gè)特別的函數(shù)。在其他語言和環(huán)境中,一個(gè)block對(duì)象有時(shí)候被稱為“閉包(closure)”。在這里,它們通常被口語化為”塊(blocks)”,除非在某些范圍它們?nèi)菀缀蜆?biāo)準(zhǔn) C 表達(dá)式的塊代碼混淆。
對(duì)于閉包(closure),有很多定義,其中閉包就是能夠讀取其它函數(shù)內(nèi)部變量的函數(shù)
“^”符號(hào)可以稱為caret ['kær?t] 也叫脫字符 插入符
返回值(^塊對(duì)象名稱)(參數(shù)列表類型) = ^(參數(shù)列表){塊對(duì)象中的代碼};
2、用處
1)簡(jiǎn)單的回調(diào)過程,不用再實(shí)現(xiàn)并調(diào)用某個(gè)函數(shù) (UIView動(dòng)畫)
2)代碼簡(jiǎn)潔,減少冗余代碼
3)與GCD結(jié)合使用 爽爆了
使用:UIView動(dòng)畫、PResentViewController、ASI
3、聲明和創(chuàng)建Block
聲明Block引用 無參無返回 無參有返回 有參無返回 有參有返回
定義Block
使用Block
typedef聲明 簡(jiǎn)稱typedef 為現(xiàn)有類型創(chuàng)建一個(gè)新的名字,或稱為類型別名,在結(jié)構(gòu)體定義,還有一些數(shù)組等地方都會(huì)用到
返回值或參數(shù)為Block的
snippet 代碼片段
4、Block對(duì)變量存取管理
1)局部變量
局部變量,在Block中只讀。Block定義時(shí)copy變量的值,在Block中作為常量使用,所以即使變量的值在Block外改變,也不影響它在Block中的值
2)__Block修飾的變量
如果要在block內(nèi)修改block外聲明的局部變量,那么一定要對(duì)該變量加__block標(biāo)記
3)Static修飾符的或全局變量
因?yàn)?/span>全局變量或靜態(tài)變量在內(nèi)存中的地址是固定的,Block在讀取該變量值的時(shí)候是直接從其所在內(nèi)存讀出,獲取到的是最新值,而不是在定義時(shí)copy的常量.
Block變量,被__Block修飾的變量稱作Block變量。 基本類型的Block變量等效于全局變量或靜態(tài)變量 但對(duì)象的block變量不會(huì)
5、Block的內(nèi)存管理
非ARC下
Block是默認(rèn)建立在棧上, 所以如果離開方法作用域, Block就會(huì)被丟棄
Block的copy、retain、release操作 不同于NSObject的copy、retain、release操作:
只要實(shí)現(xiàn)一個(gè)對(duì)周圍變量沒有引用的Block,就會(huì)顯示為是NSGlobalBlock
如果其中加入了對(duì)局部變量的引用,就是NSStackBlock
如果你對(duì)一個(gè)NSStackBlock對(duì)象使用了Block_copy()或者發(fā)送了copy消息,就會(huì)得到NSMallocBlock
1)NSGlobalBlock:retain、copy、release操作都無效;
2)NSStackBlock:retain、release操作無效,必須注意的是,NSStackBlock在函數(shù)返回后,Block內(nèi)存將被回收,即使retain也沒用。
容易犯的錯(cuò)誤是[mutableAarry addObject:stackBlock],(補(bǔ):在ARC中不用擔(dān)心此問題,因?yàn)锳RC中會(huì)默認(rèn)將實(shí)例化的Block拷貝到堆上)在函數(shù)出棧后,從mutableAarry中取到的stackBlock已經(jīng)被回收,變成了野指針。
正確的做法是先將[stackBlock copy]到堆上,然后加入數(shù)組:[mutableAarry addObject:[[stackBlock copy] autorelease]]。支持copy,copy之后生成新的NSMallocBlock類型對(duì)象。
3)NSMallocBlock支持retain、release,雖然retainCount始終是1,但內(nèi)存管理器中仍然會(huì)增加、減少計(jì)數(shù)。copy之后不會(huì)生成新的對(duì)象,只是增加了一次引用,類似retain;
4)Block_copy與copy等效,Block_release與release等效;
5)對(duì)Block不管是retain、copy、release都不會(huì)改變引用計(jì)數(shù)retainCount,retainCount始終是1;
6)盡量不要對(duì)Block使用retain操作,不方便管理。
Block的使用:UIView動(dòng)畫、presentViewController、ASI
6、Block對(duì)objc對(duì)象的內(nèi)存管理
staticObj、globalObj、instanceObj、localObj、blockObj多種類型obj對(duì)象
主要是block被copy時(shí)其塊中用到的變量的引用計(jì)數(shù)
1)非ARC
globalObj和staticObj在內(nèi)存中的位置是確定的,所以Block copy時(shí)引用計(jì)數(shù)不會(huì)改變。
instanceObj在Block copy時(shí)并沒有直接讓instanceObj對(duì)象本身引用計(jì)數(shù)加1,但卻讓self引用計(jì)數(shù)加1。所以在Block中可以直接讀寫instanceObj變量。
localObj在Block copy時(shí),系統(tǒng)自動(dòng)增加其引用計(jì)數(shù)。
blockObj在Block copy時(shí),引用計(jì)數(shù)也不會(huì)改變。
使用__block避免循環(huán)引用 __block 類 *對(duì)象 = self
void(^block)(void)= ^{
[blockSelf doSomething];
};
7、循環(huán)引用retain cycle
循環(huán)引用指兩個(gè)對(duì)象相互強(qiáng)引用了對(duì)方,即retain了對(duì)方,從而導(dǎo)致誰也釋放不了誰的內(nèi)存泄露問題。如聲明一個(gè)delegate時(shí)一般用assign而不能用retain或strong,因?yàn)槟阋坏┠敲醋隽耍艽罂赡芤?span style="color: #ff0000;">循環(huán)引用
釋放second 在fist delloc中釋放 fist的delloc什么時(shí)候執(zhí)行呢 ?
fist引用計(jì)數(shù)為0時(shí)執(zhí)行 ,然而現(xiàn)在即便是將fist從window.rootViewController上卸載下來 即釋放一次 卻發(fā)現(xiàn)second還保留著first的一次引用 到頭來還是要釋放second 形成了delegate版本的retain cycle 即循環(huán)引用
釋放_(tái)pBlock 在viewController delloc中釋放 delloc什么時(shí)候執(zhí)行呢?
viewController引用計(jì)數(shù)為0時(shí)執(zhí)行 ,然而現(xiàn)在即便是將viewController從window.rootViewController上卸載下來 即釋放一次 卻發(fā)現(xiàn)_pBlock還保留著viewController的一次引用 到頭來還是要釋放_(tái)pBlock 形成了block版本的retain cycle 即循環(huán)引用
Block的內(nèi)存管理
ARC下
在ARC下, 以下幾種情況, Block會(huì)自動(dòng)被從棧復(fù)制到堆:
1.被執(zhí)行copy方法
2.作為方法返回值
3.將Block賦值給附有__strong修飾符的id類型的類或者Blcok類型成員變量時(shí)
4.在方法名中含有usingBlock的Cocoa框架方法或者GDC的API中傳遞的時(shí)候.
Block中的對(duì)象的內(nèi)存管理
ARC下
只有在使用local變量時(shí),block會(huì)復(fù)制指針,且強(qiáng)引用指針指向的對(duì)象一次。其它如全局變量、static變量、block變量等,block不會(huì)拷貝指針,只會(huì)強(qiáng)引用指針指向的對(duì)象一次。
block的循環(huán)引用,因?yàn)閎lock在拷貝到堆上的時(shí)候,會(huì)retain其引用的外部變量,那么如果block中如果引用了它的宿主對(duì)象,那很有可能引起循環(huán)引用。如:self.myblock = ^{[self doSomething];};
使用__weak避免循環(huán)引用
Tips:
內(nèi)存主要分為
1.棧 - 由編譯器自動(dòng)分配釋放 里面的變量通常是局部變量 函數(shù)參數(shù)等
2.堆 - 一般由程序員分配釋放,若程序員不釋放,程序結(jié)束時(shí)可能由OS回收 alloc
3.全局區(qū)(靜態(tài)區(qū) static),全局變量和靜態(tài)變量的存儲(chǔ)是放在一塊的,初始化的全局變量和靜態(tài)變量在一塊區(qū)域,未初始化的全局變量和未初始化的靜態(tài)變量在相鄰的另一塊區(qū)域。- 程序結(jié)束釋放 static
People *p; People *p2 = nil;
4.另外還有一個(gè)專門放常量的地方。- 程序結(jié)束釋放 NSString *lastName = @“xue”;
lastName = @“dkjs”;
5、方法區(qū)
新聞熱點(diǎn)
疑難解答
圖片精選
網(wǎng)友關(guān)注