BLOCK
block的描述: 他是類似函數(shù)指針的一個(gè)代碼塊的內(nèi)聯(lián)封裝, 他可以將一個(gè)函數(shù)體作為對(duì)象傳遞
block的本質(zhì): 對(duì)象
block的效率: 高于函數(shù)調(diào)用
聲明一個(gè)block
? ? ? ? ? ?返回值 (^名稱)(以”逗號(hào)”分割的參數(shù)), 參數(shù)部分可以不寫參數(shù)名只寫類型
范例:
? ? ? ? ? ? ? void ?(^myFirstBlock)( int a, NSString *s, UIButton *button )
? ? ? ? ? ? BOOL (^mySecondBlock)(void)
? ? NSString * (^myThirdBlock)(CGFloat, float)
定義一個(gè)block
? ? ? ? ?^可省略的返回值(以”逗號(hào)”分割的參數(shù)){代碼塊}
范例:
? ? ? ? ^void(int a){NSLog(@"一個(gè)int參數(shù), 無返回值的block"); }?
? ? ? ? ^{ NSLog(@"一個(gè)無參數(shù),無返回值的block"); }? ? ? ? ? ? ? ??
? ? ? ? ^int(int a, int b){ NSLog( @"一個(gè)兩個(gè)int參數(shù), 返回兩個(gè)數(shù)相加的block, 結(jié)果%d", a + b ); return a + b; }
block作為函數(shù)參數(shù)
? ? ?? ? block作為參數(shù), 參數(shù)名后綴, 類型格式為: ( 返回值(^)(參數(shù)) )block名?
范例:
- (void)test:(int(^)(int))paramBlock
{
? ? ? ? NSLog( @"打印block返回結(jié)果:%d", paramBlock(10));
}
?block作為參數(shù)的函數(shù)調(diào)用:
? ? ? ? ?將block定義部分或?qū)lock對(duì)象傳入函數(shù)調(diào)用的參數(shù)部分
范例:
[self test:^(int a){
? ? ? ? return a * a;
}];
__block:
block只能只讀的訪問局部變量, 若需要修改局部變量, 需要通過__block修飾該變量, 該修飾符會(huì)使block自動(dòng)復(fù)制該對(duì)象的指針,即指針拷貝, 當(dāng)對(duì)該對(duì)象執(zhí)行寫操作時(shí), 其實(shí)就是操作其指針指向的對(duì)象進(jìn)行操作.
若不加該修飾符, block僅自動(dòng)復(fù)制需要訪問的局部變量的值副本(值拷貝), 因此只能進(jìn)行只讀操作.
__weak:
使用block特別要注意的一點(diǎn)就是防止循環(huán)引用的發(fā)生, block作為一個(gè)對(duì)象被持有者持有,若block內(nèi)部也持有該持有者將會(huì)導(dǎo)致循環(huán)引用,導(dǎo)致相互持有, 永遠(yuǎn)無法銷毀彼此的內(nèi)存問題, 若不能規(guī)避該問題, 則需要通過使用__weak修飾 block要訪問的持有者變量, 防止循環(huán)引用的發(fā)生. 尤其是block所在的self.
__strong
該修飾符在block內(nèi)的主要作用是防止__weak修飾的指針在block運(yùn)行期間被外部銷毀, 導(dǎo)致block無法順利完成原定功能. 所以當(dāng)訪問的外部變量用__weak修飾時(shí), block內(nèi)部最好再有一個(gè)__strong修飾的同類型指針指向__weak指針, 這樣就可以確保, 在block內(nèi)部的這個(gè)指針可以運(yùn)行完成. 隨著block運(yùn)行完成, __strong修飾的指針也將自動(dòng)銷毀, 進(jìn)而__weak指針也會(huì)自動(dòng)置nil.
block外部變量訪問
block可以訪問和修改全局變量
block只能只讀的訪問局部變量(值傳遞, block內(nèi)部復(fù)制了一個(gè)副本), 若加了__block修飾, 就改為引用傳遞,可修改局部變量
block底層淺談
block本身包含一個(gè)結(jié)構(gòu)體
struct __block_impl
{
void *isa;
int Flags;
int Reserved;
void *FuncPtr;
}
block分為三種類型, __block_impl的isa指針負(fù)責(zé)標(biāo)記block類型
_NSConcreteGlobalBlock: 全局靜態(tài)block, 當(dāng)block內(nèi)不訪問任何外部變量, 或者訪問的是全局作用域,成員變量的, 屬于該類型, 內(nèi)存管理方式和函數(shù)一致
_NSConcreteStackBlock 棧block, 由系統(tǒng)管理內(nèi)存, 函數(shù)返回時(shí)銷毀, 訪問的外部變量由block從棧上copy到堆上, 保證了作用域結(jié)束后, block仍然可以訪問
_NSConcreteMallocBlock 堆block, 由開發(fā)者控制, 引用計(jì)數(shù)為0時(shí)銷毀
block幾種自身copy的情況, 若觸發(fā)一下情況, block將自動(dòng)拷貝自身到堆中, 確保自身作用域內(nèi)的變量的生命周期更長(zhǎng)久
1.顯式執(zhí)行copy, [block copy];
2.block作為返回值的時(shí)候
3.block被賦值給__strong類型的對(duì)象或者block的內(nèi)部變量時(shí)
4.block作為參數(shù)傳入帶有usingBlock的CocoaFramework方法
5. block作為參數(shù)傳入GCD的API時(shí)
其他:
__typeof, __typeof__, typeof 這三個(gè)關(guān)鍵字實(shí)現(xiàn)了一個(gè)相同的功能, 獲取參數(shù)的類型名稱并返回
UIViewController *vc;
__typeof(vc) vc2;
這樣就可以在不知道vc指針類型的情況下, 再聲明一個(gè)同類型的vc2