99热99这里只有精品6国产,亚洲中文字幕在线天天更新,在线观看亚洲精品国产福利片 ,久久久久综合网

歡迎加入QQ討論群258996829
麥子學(xué)院 頭像
蘋果6袋
6
麥子學(xué)院

Objective-C 環(huán)境下實(shí)現(xiàn) defer

發(fā)布時(shí)間:2016-10-02 23:05  回復(fù):0  查看:2285   最后回復(fù):2016-10-02 23:05  

這篇文章會(huì)對(duì) libextobjc 中的一小部分代碼進(jìn)行分析,也是如何擴(kuò)展 Objective-C 語(yǔ)言系列文章的第一篇,筆者會(huì)從 libextobjc 中選擇一些黑魔法進(jìn)行介紹。

對(duì) Swift 稍有了解的人都知道,defer 在 Swift 語(yǔ)言中是一個(gè)關(guān)鍵字;在 defer 代碼塊中的代碼,會(huì)在作用域結(jié)束時(shí)執(zhí)行。在這里,我們會(huì)使用一些神奇的方法在 Objective-C 中實(shí)現(xiàn) defer。

如果你已經(jīng)非常了解 defer 的作用,你可以跳過(guò)第一部分的內(nèi)容,直接看 Variable Attributes

 

關(guān)于 defer

defer 是 Swift 在 2.0 時(shí)代加入的一個(gè)關(guān)鍵字,它提供了一種非常安全并且簡(jiǎn)單的方法聲明一個(gè)在作用域結(jié)束時(shí)執(zhí)行的代碼塊。

如果你在 Swift Playground 中輸入以下代碼:

func hello() {

defer {

print("4")

}

if true {

defer {

print("2")

}

defer {

print("1")

}

}

print("3")

}

hello()

 

控制臺(tái)的輸出會(huì)是這樣的:

1

2

3

4

 

你可以仔細(xì)思考一下為什么會(huì)有這樣的輸出,并在 Playground 使用 defer 寫一些簡(jiǎn)單的代碼,相信你可以很快理解它是如何工作的。

如果對(duì) defer 的作用仍然不是非常了解,可以看 guard & defer 這篇文章的后半部分。

 

 

Variable Attributes

 

libextobjc 實(shí)現(xiàn)的 defer 并沒(méi)有基于 Objective-C 的動(dòng)態(tài)特性,甚至也沒(méi)有調(diào)用已有的任何方法,而是使用了 Variable Attributes 這一特性。

同樣在 GCC 中也存在用于修飾函數(shù)的 Function Attributes

 

 

Variable Attributes 其實(shí)是 GCC 中用于描述變量的一種修飾符。我們可以使用 __attribute__ 來(lái)修飾一些變量來(lái)參與靜態(tài)分析等編譯過(guò)程;而在 Cocoa Touch 中很多的宏其實(shí)都是通過(guò) __attribute__ 來(lái)實(shí)現(xiàn)的,例如:

#define NS_ROOT_CLASS __attribute__((objc_root_class))

 

而 cleanup 就是在這里會(huì)使用的變量屬性:

The cleanup attribute runs a function when the variable goes out of scope. This attribute can only be applied to auto function scope variables; it may not be applied to parameters or variables with static storage duration. The function must take one parameter, a pointer to a type compatible with the variable. The return value of the function (if any) is ignored.

 

 

GCC 文檔中對(duì) cleanup 屬性的介紹告訴我們,在 cleanup 中必須傳入只有一個(gè)參數(shù)的函數(shù)并且這個(gè)參數(shù)需要與變量的類型兼容。

如果上面這句比較繞口的話很難理解,可以通過(guò)一個(gè)簡(jiǎn)單的例子理解其使用方法:

void cleanup_block(int *a) {

printf("%d\\n", *a);

}

int variable __attribute__((cleanup(cleanup_block))) = 2;

 

在 variable 這個(gè)變量離開(kāi)作用域之后,就會(huì)自動(dòng)將這個(gè)變量的指針傳入 cleanup_block 中,調(diào)用 cleanup_block 方法來(lái)進(jìn)行『清理』工作。

 

實(shí)現(xiàn) defer

 

到目前為止已經(jīng)有了實(shí)現(xiàn) defer 需要的全部知識(shí),我們可以開(kāi)始分析 libextobjc 是怎么做的。

在 libextobjc 中并沒(méi)有使用 defer 這個(gè)名字,而是使用了 onExit(表示代碼是在退出作用域時(shí)執(zhí)行)

為了使 onExit 在使用時(shí)更加明顯,libextobjc 通過(guò)一些其它的手段使得我們?cè)诿看问褂?nbsp;onExit 時(shí)都需要添加一個(gè) 符號(hào)

 

{

@onExit {

NSLog("Log when out of scope.");

};

NSLog("Log before out of scope.");

}

 

onExit 其實(shí)只是一個(gè)精心設(shè)計(jì)的宏:

#define onExit \\

ext_keywordify \\

__strong ext_cleanupBlock_t metamacro_concat(ext_exitBlock_, __LINE__) __attribute__((cleanup(ext_executeCleanupBlock), unused)) = ^

 

既然它只是一個(gè)宏,那么上面的代碼其實(shí)是可以展開(kāi)的:

autoreleasepool {}

__strong ext_cleanupBlock_t ext_exitBlock_19 __attribute__((cleanup(ext_executeCleanupBlock), unused)) = ^ {

NSLog("Log when out of scope.");

};

 

這里,我們分幾個(gè)部分來(lái)分析上面的代碼片段是如何實(shí)現(xiàn) defer 的功能的:

ext_keywordify 也是一個(gè)宏定義,它通過(guò)添加在宏之前添加 autoreleasepool {} 強(qiáng)迫 onExit 前必須加上 符號(hào)。

#define ext_keywordify autoreleasepool {}

ext_cleanupBlock_t 是一個(gè)類型:

 

typedef void (^ext_cleanupBlock_t)();

 

metamacro_concat(ext_exitBlock_, __LINE__) 會(huì)將 ext_exitBlock 和當(dāng)前行號(hào)拼接成一個(gè)臨時(shí)的的變量名,例如:ext_exitBlock_19

__attribute__((cleanup(ext_executeCleanupBlock), unused)) 將 cleanup 函數(shù)設(shè)置為 ext_executeCleanupBlock;并將當(dāng)前變量 ext_exitBlock_19 標(biāo)記為 unused 來(lái)抑制 Unused variable 警告。

變量 ext_exitBlock_19 的值為 ^{ NSLog("Log when out of scope."); },是一個(gè)類型為 ext_cleanupBlock_t 的 block

在這個(gè)變量離開(kāi)作用域時(shí),會(huì)把上面的 block 的指針傳入 cleanup 函數(shù),也就是 ext_executeCleanupBlock

void ext_executeCleanupBlock (__strong ext_cleanupBlock_t *block) {

(*block)();

}

 

這個(gè)函數(shù)的作用只是簡(jiǎn)單的執(zhí)行傳入的 block,它滿足了 GCC 文檔中對(duì) cleanup 函數(shù)的幾個(gè)要求:

只能包含一個(gè)參數(shù)

參數(shù)的類型是一個(gè)指向變量類型的指針

函數(shù)的返回值是 void

 

總結(jié)

 

這是分析 libextobjc 框架的第一篇文章,也是比較簡(jiǎn)短的一篇,因?yàn)槲覀冊(cè)谌粘i_(kāi)發(fā)中基本上用不到這個(gè)框架提供的 API,但是它依然會(huì)為我們展示了很多編程上的黑魔法。

 

 

文章來(lái)源:iOS猿吧

您還未登錄,請(qǐng)先登錄

熱門帖子

最新帖子

?