總結(jié)
一、理解“塊”這一概念
1、塊的基礎(chǔ)知識(shí)
(1)、概念:
塊用“^”符號(hào)來(lái)表示,后面跟著一對(duì)花括號(hào),括號(hào)里面是塊的實(shí)現(xiàn)代碼。例如:
^{
// Block implementation here
}
塊其實(shí)就是個(gè)值,也有其相關(guān)類型,可以把塊賦給變量并使用它。塊類型的語(yǔ)法與函數(shù)指針近似。例如,無(wú)參數(shù)無(wú)返回值的塊類型定義如下:
void (^someBlock)() = ^{
// Block implementation here
};
因此,我們可以把塊類型的語(yǔ)法結(jié)構(gòu)寫(xiě)成這樣子,如下:
return_type (^block_name) (parameters)
例子:
int (^addBlock) (int a, int b) = ^(int a, int b) {
return a + b;
};
(2)、塊的內(nèi)部結(jié)構(gòu)
塊本身也是對(duì)象,在存放塊對(duì)象的內(nèi)存區(qū)域中,首個(gè)變量是指向Class對(duì)象的指針(isa),下圖描述了塊對(duì)象的內(nèi)存布局。

在內(nèi)存布局中,最重要的就是invoke變量,這是個(gè)函數(shù)指針,指向塊的實(shí)現(xiàn)代碼。
(3)、全局塊、棧塊及堆塊
定義塊的時(shí)候,其所占的內(nèi)存區(qū)域是分配在棧中的。
若要在塊定義的范圍之外使用,則需給塊對(duì)象發(fā)送copy消息以拷貝之,這樣就把塊從棧復(fù)制到堆了,拷貝后的塊就可以在定義它的那個(gè)范圍之外使用了。
塊也可以定義成全局的。
2、為常用的塊類型創(chuàng)建typedef
為了隱藏復(fù)雜的塊類型,需要使用類型定義,如:
typedef int (^EOCSomeBlock) (BOOL flag, int value);
EOCSomeBlock block = ^(BOOL flag, int value) {
//Implementation
};
3、用 handler 塊降低代碼分散程度
在程序里使用delegate的地方都可以使用Block來(lái)替換,其使用方法如下:
typedef void (^EOCNetworkFetcherCompletionHandler) (NSData *data, NSError *error);
@interface EOCNetworkFetcher : NSObject
- (void)startWithCompletionHandler:(EOCNetworkFetcherCompletionHandler)handler;
@end
4、用塊引用其所屬對(duì)象時(shí)不要出現(xiàn)保留環(huán)
1、如果塊所捕獲的對(duì)象直接或間接地保留了塊本身,那么久得當(dāng)心保留環(huán)的問(wèn)題。
2、一定要找個(gè)適當(dāng)?shù)臅r(shí)機(jī)解除保留環(huán)。
5、多用派發(fā)隊(duì)列,少用同步鎖
1、有種簡(jiǎn)單而高效的辦法可以代替同步塊或鎖對(duì)象,那就是使用“串行同步隊(duì)列”。
dispatch_queue_t _syncQueue = dispatch_queue_create("com.effectiveobjectivec.syncQueue", NULL);
- (NSString *)someString {
__block NSString *localSomeString;
dispatch_sync(_syncQueue, ^{
localSomeString = _someString;
});
return localSomeString;
}
- (void)setSomeString:(NSString *)someString {
dispatch_sync(_syncQueue, ^{
_someString = someString;
});
}
進(jìn)一步優(yōu)化,可以將設(shè)置實(shí)例變量的方法中所用到的塊同步改成異步:dispatch_async(_syncQueue, ^{});