ReactiveCocoa 中 奇妙無比的“宏”魔法

前言

在ReactiveCocoa 中,開源庫(kù)作者為我們提供了很多種魔法,“黑”魔法,“紅”魔法……今天就讓先來看看“紅”魔法卖丸。

在ReactiveCocoa 中,封裝了很多非常實(shí)用的“宏”盏道,使用這些“宏”為我們開發(fā)帶來了很多的便利稍浆。

今天就來盤點(diǎn)一下RAC中的宏是如何實(shí)現(xiàn)的。

目錄

  • 1.關(guān)于宏
  • 2.ReactiveCocoa 中的元宏
  • 3.ReactiveCocoa 中常用的宏

一. 關(guān)于宏

(Macro)猜嘱,是一種批量處理的稱謂衅枫。

在編程領(lǐng)域里的宏是一種抽象(Abstraction),它根據(jù)一系列預(yù)定義的規(guī)則替換一定的文本模式朗伶。解釋器編譯器在遇到宏時(shí)會(huì)自動(dòng)進(jìn)行這一模式替換弦撩。絕大多數(shù)情況下,“宏”這個(gè)詞的使用暗示著將小命令或動(dòng)作轉(zhuǎn)化為一系列指令论皆。

宏的用途在于自動(dòng)化頻繁使用的序列或者是獲得一種更強(qiáng)大的抽象能力益楼。
計(jì)算機(jī)語言如C語言匯編語言有簡(jiǎn)單的宏系統(tǒng),由編譯器匯編器的預(yù)處理器實(shí)現(xiàn)纯丸。C語言的宏預(yù)處理器的工作只是簡(jiǎn)單的文本搜索和替換偏形,使用附加的文本處理語言如M4静袖,C程序員可以獲得更精巧的宏觉鼻。

Lisp類語言如Common LispScheme有更精巧的宏系統(tǒng):宏的行為如同是函數(shù)對(duì)自身程序文本的變形,并且可以應(yīng)用全部語言來表達(dá)這種變形队橙。一個(gè)C宏可以定義一段語法的替換坠陈,然而一個(gè)Lisp的宏卻可以控制一節(jié)代碼的計(jì)算。

對(duì)于編譯語言來說捐康,所有的宏都是在預(yù)編譯的時(shí)候被展開的仇矾,所以在lex進(jìn)行詞法掃描生成Token,詞法分析過程之前解总,所有的宏都已經(jīng)被展開完成了贮匕。

對(duì)于Xcode,預(yù)處理或者預(yù)編譯階段是可以直接查看的花枫。

隨便寫一個(gè)宏刻盐,然后打開Xcode右上方的Assistant,選擇“Preprocess”就可以看到該文件預(yù)處理之后的樣子了劳翰《匦浚可以看到左邊的@weakify(self) 被轉(zhuǎn)換成了右邊的兩行代碼了。

關(guān)于這個(gè)Xcode的這個(gè)功能還有2點(diǎn)補(bǔ)充說明:

1.不同階段的Preprocessed可能不同佳簸,要根據(jù)你的目標(biāo)去選擇預(yù)處理的條件乙墙。

比如這里就有5種預(yù)編譯的種類可以選擇。

2.宏經(jīng)過預(yù)編譯之后出來的代碼,是可以用來檢測(cè)宏寫的是否正確的听想,但是無法看到宏被展開的具體過程腥刹。這意味著我們可以通過Xcode這個(gè)功能來查看宏的作用,但是無法知道宏的具體實(shí)現(xiàn)汉买。具體實(shí)現(xiàn)還是需要通過查看源碼來分析肛走。

ReactiveCocoa中的宏,如果不查看源碼分析录别,會(huì)覺得那些宏都像魔法一樣奇妙無比朽色,接下來就來解開“宏”魔法的神秘面紗。

二. ReactiveCocoa 中的元宏

在ReactiveCocoa的宏中组题,作者定義了這么一些基礎(chǔ)的宏葫男,作為“元宏”,它們是構(gòu)成之后復(fù)雜宏的基礎(chǔ)崔列。在分析常用宏之前梢褐,必須要先分析清楚這些元宏的具體實(shí)現(xiàn)。

1. metamacro_stringify(VALUE)


#define metamacro_stringify(VALUE) \
        metamacro_stringify_(VALUE)

#define metamacro_stringify_(VALUE) # VALUE

metamacro_stringify( )這個(gè)宏用到了#的用法赵讯。#在宏中代表把宏的參數(shù)變?yōu)橐粋€(gè)字符串盈咳。這個(gè)宏的目的和它的名字一樣明顯,把入?yún)ALUE轉(zhuǎn)換成一個(gè)字符串返回边翼。

這里可能就有人有疑問鱼响,為啥要包裝一層,不能直接寫成下面這樣:


#define metamacro_stringify(VALUE)  # VALUE


語意確實(shí)也沒有變组底,但是有種特殊情況下就會(huì)出現(xiàn)問題丈积。

舉個(gè)例子:


#define NUMBER   10
#define ADD(a,b) (a+b)
NSLog(@"%d+%d=%d",NUMBER, NUMBER, ADD(NUMBER,NUMBER));

輸出如下:


10+10=20

這樣子確實(shí)是沒有問題,但是稍作修改就會(huì)有問題债鸡。


#define STRINGIFY(S) #S
#define CALCULATE(A,B)  (A##10##B)

NSLog(@"int max: %s",STRINGIFY(INT_MAX));
NSLog(@"%d", CALCULATE(NUMBER,NUMBER));

如果是這種情況下江滨,第二個(gè)NSLog打印是會(huì)編譯錯(cuò)誤的。上面兩句經(jīng)過預(yù)編譯之后厌均,宏會(huì)被展開成下面這個(gè)樣子:


NSLog(@"int max: %s","INT_MAX");
NSLog(@"%d", (NUMBER10NUMBER));

可以發(fā)現(xiàn)唬滑,宏并沒有再次被展開。解決辦法也很簡(jiǎn)單棺弊,就是把宏包裝一層晶密,寫一個(gè)轉(zhuǎn)接宏出來。


#define CALCULATE(A,B)   _CALCULATE(A,B)   // 轉(zhuǎn)換宏
#define _CALCULATE(A,B)  A##10##B

再次測(cè)試一下镊屎,這里我們使用官方的metamacro_stringify


NSLog(@"int max: %s",metamacro_stringify(INT_MAX));
NSLog(@"%d", CALCULATE(NUMBER,NUMBER));

這樣最終打印出來的結(jié)果和我們想要的一致惹挟,沒有問題。


2147483647
101010

CALCULATE(NUMBER,NUMBER) 第一層轉(zhuǎn)換成 _CALCULATE(10,10)缝驳,接著第二次轉(zhuǎn)換成10##10##10连锯,也就是101010归苍。

當(dāng)然這里是2層轉(zhuǎn)換,如果有多層轉(zhuǎn)換就需要更多個(gè)轉(zhuǎn)換宏了运怖。


NSLog(@"%d", CALCULATE(STRINGIFY(NUMBER),STRINGIFY(NUMBER)));


上面這個(gè)例子就是3層了拼弃,按照之前我們的寫法還是編譯報(bào)錯(cuò)。如果是超過2摇展,3層的多層的情況吻氧,就該考慮考慮宏設(shè)計(jì)的語意的問題,盡量不讓使用者產(chǎn)生錯(cuò)誤的用法咏连。

2. metamacro_concat(A, B)


#define metamacro_concat(A, B) \
        metamacro_concat_(A, B)
#define metamacro_concat_(A, B) A ## B

這個(gè)宏就是用來合并入?yún)盯孙,B到一起。在RAC里面主要用這個(gè)方法來合成另外一個(gè)宏的名字祟滴。

3. metamacro_argcount(...) 和 metamacro_at(N, ...)

metamacro_argcount(...)這個(gè)宏設(shè)計(jì)的也非常巧妙振惰,它是用來獲取參數(shù)個(gè)數(shù)的。由于宏展開是在預(yù)編譯時(shí)期的垄懂,所以它在預(yù)編譯時(shí)期獲取參數(shù)個(gè)數(shù)的骑晶,其他非宏的方法都是在運(yùn)行時(shí)獲取參數(shù)個(gè)數(shù)的。


#define metamacro_argcount(...) \
        metamacro_at(20, __VA_ARGS__, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1)


這里會(huì)調(diào)用metamacro_at(N, ...)宏草慧。


#define metamacro_at(N, ...) \
        metamacro_concat(metamacro_at, N)(__VA_ARGS__)

把這個(gè)宏展開桶蛔,于是得到:


#define metamacro_at(N, ...) \
        metamacro_atN(__VA_ARGS__)

于是通過metamacro_concat合成命令,就得到了一連串的metamacro_atN宏命令:


#define metamacro_at0(...) metamacro_head(__VA_ARGS__)
#define metamacro_at1(_0, ...) metamacro_head(__VA_ARGS__)
#define metamacro_at2(_0, _1, ...) metamacro_head(__VA_ARGS__)
#define metamacro_at3(_0, _1, _2, ...) metamacro_head(__VA_ARGS__)
#define metamacro_at4(_0, _1, _2, _3, ...) metamacro_head(__VA_ARGS__)
#define metamacro_at5(_0, _1, _2, _3, _4, ...) metamacro_head(__VA_ARGS__)
#define metamacro_at6(_0, _1, _2, _3, _4, _5, ...) metamacro_head(__VA_ARGS__)
#define metamacro_at7(_0, _1, _2, _3, _4, _5, _6, ...) metamacro_head(__VA_ARGS__)
#define metamacro_at8(_0, _1, _2, _3, _4, _5, _6, _7, ...) metamacro_head(__VA_ARGS__)
#define metamacro_at9(_0, _1, _2, _3, _4, _5, _6, _7, _8, ...) metamacro_head(__VA_ARGS__)
#define metamacro_at10(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, ...) metamacro_head(__VA_ARGS__)
#define metamacro_at11(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, ...) metamacro_head(__VA_ARGS__)
#define metamacro_at12(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, ...) metamacro_head(__VA_ARGS__)
#define metamacro_at13(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, ...) metamacro_head(__VA_ARGS__)
#define metamacro_at14(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, ...) metamacro_head(__VA_ARGS__)
#define metamacro_at15(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, ...) metamacro_head(__VA_ARGS__)
#define metamacro_at16(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, ...) metamacro_head(__VA_ARGS__)
#define metamacro_at17(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, ...) metamacro_head(__VA_ARGS__)
#define metamacro_at18(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, ...) metamacro_head(__VA_ARGS__)
#define metamacro_at19(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, ...) metamacro_head(__VA_ARGS__)
#define metamacro_at20(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, ...) metamacro_head(__VA_ARGS__)



可見N的取值只能從0到20漫谷。


#define metamacro_head(...) \
        metamacro_head_(__VA_ARGS__, 0)
#define metamacro_head_(FIRST, ...) FIRST

metamacro_head展開之后變成:


#define metamacro_head(FIRST,..., 0)  FIRST

metamacro_head的意圖就很明顯仔雷,是用來獲取后面可變?nèi)雲(yún)⒌牡谝粋€(gè)參數(shù)。

回到metamacro_atN宏上面來抖剿,那么把它展開就是下面這樣:


#define metamacro_atN(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, ... , _N, ...) metamacro_head(__VA_ARGS__)


當(dāng)然朽寞,N的取值還是從0到20,那么metamacro_atN宏獲取到的值就是可變參數(shù)列表里面的第N個(gè)參數(shù)值斩郎。參數(shù)從0開始。

再回到最初的metamacro_argcount(...)宏喻频,目前展開到這一步:



#define metamacro_argcount(...) \
        metamacro_at20(__VA_ARGS__, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1)


由于__VA_ARGS__個(gè)數(shù)不能超過20個(gè)缩宜,所以必定是在0-19之間。


metamacro_at20(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, ..., 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1) metamacro_head(__VA_ARGS__)


假設(shè)入?yún)⑹怯?個(gè):


metamacro_argcount(@"1",@"2",@"3",@"4",@"5");

先把5個(gè)參數(shù)放入metamacro_at20的前五個(gè)位置甥温。然后從第6個(gè)位置開始倒序插入20-1的數(shù)字锻煌。如下圖:

我們可以把倒序的數(shù)字想象成一把尺子,是用來衡量或者指示當(dāng)前有多少個(gè)參數(shù)的姻蚓。尺子的最左邊對(duì)齊上面20個(gè)空位的第一位宋梧,尺子后面多出來的部分,取出來狰挡,然后進(jìn)行metamacro_head操作捂龄,取出第一位參數(shù)释涛,這個(gè)數(shù)字就是整個(gè)參數(shù)的個(gè)數(shù)了。這把虛擬的“尺子”是會(huì)左右對(duì)齊的倦沧,具體的位置就要根據(jù)填入?yún)?shù)的個(gè)數(shù)來決定的唇撬。

這個(gè)宏的原理也很簡(jiǎn)單,20 - ( 20 - n )= n展融。metamacro_argcount(...) 宏就是這樣在預(yù)編譯時(shí)期獲取到參數(shù)個(gè)數(shù)的窖认。

作者也標(biāo)明了,這個(gè)宏的設(shè)計(jì)靈感來自于P99神庫(kù)告希,有興趣的同學(xué)可以去看看這個(gè)庫(kù)扑浸。

4. metamacro_foreach(MACRO, SEP, ...) 和 metamacro_foreach_cxt(MACRO, SEP, CONTEXT, ...)

先來分析分析metamacro_foreach(MACRO, SEP, ...) 宏:


#define metamacro_foreach(MACRO, SEP, ...) \
        metamacro_foreach_cxt(metamacro_foreach_iter, SEP, MACRO, __VA_ARGS__)

看到定義就知道m(xù)etamacro_foreach(MACRO, SEP, ...) 和 metamacro_foreach_cxt(MACRO, SEP, CONTEXT, ...) 是一樣的作用。前者只不過比后者少了一個(gè)foreach的迭代子燕偶。

1. metamacro_foreach_cxt(MACRO, SEP, CONTEXT, ...)宏

再來看看metamacro_foreach_cxt(MACRO, SEP, CONTEXT, ...)宏的定義首装。



#define metamacro_foreach_cxt(MACRO, SEP, CONTEXT, ...) \
        metamacro_concat(metamacro_foreach_cxt, metamacro_argcount(__VA_ARGS__))(MACRO, SEP, CONTEXT, __VA_ARGS__)


那么之前的metamacro_foreach(MACRO, SEP, ...)宏就可以等價(jià)于


metamacro_concat(metamacro_foreach_cxt, metamacro_argcount(__VA_ARGS__))(metamacro_foreach_iter, SEP, MACRO, __VA_ARGS__)

回到metamacro_foreach_cxt(MACRO, SEP, CONTEXT, ...)宏的展開表達(dá)式上面來,假設(shè)__VA_ARGS__的參數(shù)個(gè)數(shù)為N杭跪。

metamacro_concat 宏 和 metamacro_argcount 宏上面介紹過了仙逻,那么可以繼續(xù)把宏展開成下面的樣子:


metamacro_foreach_cxtN(MACRO, SEP, CONTEXT, __VA_ARGS__)

這里又是利用metamacro_concat 宏動(dòng)態(tài)的合并成了另一個(gè)宏的例子。


#define metamacro_foreach_cxt0(MACRO, SEP, CONTEXT)
#define metamacro_foreach_cxt1(MACRO, SEP, CONTEXT, _0) MACRO(0, CONTEXT, _0)

#define metamacro_foreach_cxt2(MACRO, SEP, CONTEXT, _0, _1) \
    metamacro_foreach_cxt1(MACRO, SEP, CONTEXT, _0) \
    SEP \
    MACRO(1, CONTEXT, _1)

#define metamacro_foreach_cxt3(MACRO, SEP, CONTEXT, _0, _1, _2) \
    metamacro_foreach_cxt2(MACRO, SEP, CONTEXT, _0, _1) \
    SEP \
    MACRO(2, CONTEXT, _2)

#define metamacro_foreach_cxt4(MACRO, SEP, CONTEXT, _0, _1, _2, _3) \
    metamacro_foreach_cxt3(MACRO, SEP, CONTEXT, _0, _1, _2) \
    SEP \
    MACRO(3, CONTEXT, _3)

#define metamacro_foreach_cxt5(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4) \
    metamacro_foreach_cxt4(MACRO, SEP, CONTEXT, _0, _1, _2, _3) \
    SEP \
    MACRO(4, CONTEXT, _4)

#define metamacro_foreach_cxt6(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5) \
    metamacro_foreach_cxt5(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4) \
    SEP \
    MACRO(5, CONTEXT, _5)

#define metamacro_foreach_cxt7(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6) \
    metamacro_foreach_cxt6(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5) \
    SEP \
    MACRO(6, CONTEXT, _6)

#define metamacro_foreach_cxt8(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7) \
    metamacro_foreach_cxt7(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6) \
    SEP \
    MACRO(7, CONTEXT, _7)

#define metamacro_foreach_cxt9(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8) \
    metamacro_foreach_cxt8(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7) \
    SEP \
    MACRO(8, CONTEXT, _8)

#define metamacro_foreach_cxt10(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9) \
    metamacro_foreach_cxt9(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8) \
    SEP \
    MACRO(9, CONTEXT, _9)

#define metamacro_foreach_cxt11(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10) \
    metamacro_foreach_cxt10(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9) \
    SEP \
    MACRO(10, CONTEXT, _10)

#define metamacro_foreach_cxt12(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11) \
    metamacro_foreach_cxt11(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10) \
    SEP \
    MACRO(11, CONTEXT, _11)

#define metamacro_foreach_cxt13(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12) \
    metamacro_foreach_cxt12(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11) \
    SEP \
    MACRO(12, CONTEXT, _12)

#define metamacro_foreach_cxt14(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13) \
    metamacro_foreach_cxt13(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12) \
    SEP \
    MACRO(13, CONTEXT, _13)

#define metamacro_foreach_cxt15(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14) \
    metamacro_foreach_cxt14(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13) \
    SEP \
    MACRO(14, CONTEXT, _14)

#define metamacro_foreach_cxt16(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15) \
    metamacro_foreach_cxt15(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14) \
    SEP \
    MACRO(15, CONTEXT, _15)

#define metamacro_foreach_cxt17(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16) \
    metamacro_foreach_cxt16(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15) \
    SEP \
    MACRO(16, CONTEXT, _16)

#define metamacro_foreach_cxt18(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17) \
    metamacro_foreach_cxt17(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16) \
    SEP \
    MACRO(17, CONTEXT, _17)

#define metamacro_foreach_cxt19(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18) \
    metamacro_foreach_cxt18(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17) \
    SEP \
    MACRO(18, CONTEXT, _18)

#define metamacro_foreach_cxt20(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19) \
    metamacro_foreach_cxt19(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18) \
    SEP \
    MACRO(19, CONTEXT, _19)



把上述的metamacro_foreach_cxtN的定義抽象一下:


#define metamacro_foreach_cxtN(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, … ,_N - 1) \
    metamacro_foreach_cxtN - 1(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, … ,_N - 2) \
    SEP \
    MACRO(N - 1, CONTEXT, _N - 1)


當(dāng)然涧尿,在RAC中N的取值范圍是[0,20]系奉。我們還是假設(shè)N的定義域是全體非負(fù)整數(shù)組成的集合N(數(shù)學(xué)中的非負(fù)整數(shù)集合的標(biāo)志) 。那么我們把metamacro_foreach_cxtN完全展開到不能展開為止:


    MACRO(0, CONTEXT, _0) \
    SEP \
    MACRO(1, CONTEXT, _1) \
    SEP \
    MACRO(2, CONTEXT, _2) \
    SEP \
    MACRO(3, CONTEXT, _3) \
     ……
     ……
     ……
     ……
     ……
     ……

     SEP \
    MACRO(N - 4, CONTEXT, _N - 4) \
     SEP \
    MACRO(N - 3, CONTEXT, _N - 3) \
     SEP \
    MACRO(N - 2, CONTEXT, _N - 2) \
     SEP \
    MACRO(N - 1, CONTEXT, _N - 1)


metamacro_foreach_cxtN(MACRO, SEP, CONTEXT, ...)姑廉,這個(gè)宏的意圖也就很明顯了缺亮,從可變參數(shù)列表里面讀取出個(gè)數(shù),然后把每個(gè)參數(shù)都進(jìn)行一次MACRO(N - 1, CONTEXT, _N - 1)操作桥言,每個(gè)操作直接用SEP作為分隔符進(jìn)行分隔萌踱。

metamacro_foreach_cxt(MACRO, SEP, CONTEXT, ...)這個(gè)宏的設(shè)計(jì)靈感也來自于P99庫(kù)。

用到這個(gè)宏最著名的的宏就是weakify(...)了号阿,下面來簡(jiǎn)要的看看是如何利用metamacro_foreach_cxtN(MACRO, SEP, CONTEXT, ...)巧妙的實(shí)現(xiàn)weakify(...)的并鸵。


#define weakify(...) \
    rac_keywordify \
    metamacro_foreach_cxt(rac_weakify_,, __weak, __VA_ARGS__)


使用weakify和平時(shí)我們自己寫的weakSelf最大的區(qū)別就是,weakify后面是可以跟多個(gè)參數(shù)的扔涧,最多多達(dá)20個(gè)园担。weakify可以一口氣把參數(shù)列表里面所有的參數(shù)都進(jìn)行weak操作。

weakify(...)的重點(diǎn)之一就在metamacro_foreach_cxt操作上枯夜。假設(shè)傳入2個(gè)參數(shù)弯汰,self和str,進(jìn)行展開之后得到:



    MACRO(0, CONTEXT, _0) \
    SEP \
    MACRO(1, CONTEXT, _1)

MACRO = rac_weakify_湖雹,CONTEXT = __weak咏闪,SEP 為 空格 ,代入?yún)?shù):


 rac_weakify_(0,__weak,self) \
 rac_weakify_(1,__weak,str) 

注意摔吏,替換完成之后鸽嫂,兩個(gè)宏是連在一起的纵装,中間沒有分號(hào)!分隔符SEP目前是空格溪胶。最后一步就是替換掉rac_weakify_:


#define rac_weakify_(INDEX, CONTEXT, VAR) \
    CONTEXT __typeof__(VAR) metamacro_concat(VAR, _weak_) = (VAR);

注意這里的INDEX是廢參數(shù)搂擦,并沒有被用到。

展開上面的宏:


__weak __typeof__(self) self_weak_ = (self)哗脖;__weak __typeof__(str) str_weak_ = (str)瀑踢;


注意,rac_weakify_是自帶分號(hào)的才避,如果此處沒有分號(hào)橱夭,這里會(huì)出現(xiàn)編譯錯(cuò)誤。

最終@weakify(self桑逝,str) 就會(huì)在預(yù)編譯期間被替換成



@autoreleasepool {} __weak __typeof__(self) self_weak_ = (self)棘劣;__weak __typeof__(str) str_weak_ = (str);

注意中間是沒有換行的楞遏,此處宏展開之后就是一行茬暇。

metamacro_foreach_cxt(MACRO, SEP, CONTEXT, ...)分析完畢之后再回過來看看metamacro_foreach(MACRO, SEP, ...)

2. metamacro_foreach(MACRO, SEP, ...)

metamacro_concat(metamacro_foreach_cxt, metamacro_argcount(__VA_ARGS__))(metamacro_foreach_iter, SEP, MACRO, __VA_ARGS__)


此時(shí)同樣可以假設(shè)參數(shù)個(gè)數(shù)為N,那么上述宏展開可以變成下面的樣子:



metamacro_foreach_cxtN(metamacro_foreach_iter, SEP, MACRO, __VA_ARGS__)


這里的MACRO = metamacro_foreach_iter寡喝,SEP = SEP 糙俗, CONTEXT = MACRO。


    metamacro_foreach_iter(0, MACRO, _0) \
    SEP \
    metamacro_foreach_iter(1, MACRO, _1) \
    SEP \
    metamacro_foreach_iter(2, MACRO, _2) \
    SEP \
    metamacro_foreach_iter(3, MACRO, _3) \
     ……
     ……
     ……
     ……
     ……
     ……

     SEP \
    metamacro_foreach_iter(N - 4, MACRO, _N - 4) \
     SEP \
    metamacro_foreach_iter(N - 3, MACRO, _N - 3) \
     SEP \
    metamacro_foreach_iter(N - 2, MACRO, _N - 2) \
     SEP \
    metamacro_foreach_iter(N - 1, MACRO, _N - 1)


metamacro_foreach_iter 定義如下:



#define metamacro_foreach_iter(INDEX, MACRO, ARG) MACRO(INDEX, ARG)


繼續(xù)展開得到下面的式子:


    MACRO(0, _0) \
    SEP \
    MACRO(1, _1) \
    SEP \
    MACRO(2, _2) \
    SEP \
    MACRO(3, _3) \
     ……
     ……
     ……
     ……
     ……
     ……

     SEP \
    MACRO(N - 4, _N - 4) \
     SEP \
    MACRO(N - 3, _N - 3) \
     SEP \
    MACRO(N - 2, _N - 2) \
     SEP \
    MACRO(N - 1, _N - 1)


從最終的展開式子上來看预鬓,metamacro_foreach(MACRO, SEP, ...) 就比 metamacro_foreach_cxt(MACRO, SEP, CONTEXT, ...) 少了一個(gè)CONTEXT巧骚。

metamacro_foreach(MACRO, SEP, ...)這個(gè)宏的典型例子就是熟知的strongify(...)的實(shí)現(xiàn)。



#define strongify(...) \
    rac_keywordify \
    _Pragma("clang diagnostic push") \
    _Pragma("clang diagnostic ignored \"-Wshadow\"") \
    metamacro_foreach(rac_strongify_,, __VA_ARGS__) \
    _Pragma("clang diagnostic pop")


通過上面的分析格二,我們直接替換結(jié)果劈彪,MACRO = rac_strongify_ ,SEP = 空格顶猜。


    rac_strongify_(0, _0) \
    rac_strongify_(1, _1) \
    rac_strongify_(2, _2) \
    rac_strongify_(3, _3) \
     ……
     ……
     ……
     ……
     ……
     ……

    rac_strongify_(N - 4, _N - 4) \
    rac_strongify_(N - 3, _N - 3) \
    rac_strongify_(N - 2, _N - 2) \
    rac_strongify_(N - 1, _N - 1)


接下來替換掉rac_strongify_


#define rac_strongify_(INDEX, VAR) \
    __strong __typeof__(VAR) VAR = metamacro_concat(VAR, _weak_);


同樣的沧奴,這里的INDEX也是一個(gè)廢參數(shù),也沒有用到驶兜。rac_strongify_同樣的自帶分號(hào)扼仲,如果此處沒有分號(hào),SEP此時(shí)也是空格抄淑,編譯就直接報(bào)錯(cuò)。

最終就轉(zhuǎn)換成如下的樣子:


__strong __typeof__(self) self = self_weak_;


5. metamacro_foreach_cxt_recursive(MACRO, SEP, CONTEXT, ...)

先來看看定義:


#define metamacro_foreach_cxt_recursive(MACRO, SEP, CONTEXT, ...) \
        metamacro_concat(metamacro_foreach_cxt_recursive, metamacro_argcount(__VA_ARGS__))(MACRO, SEP, CONTEXT, __VA_ARGS__)



假設(shè)可變參數(shù)個(gè)數(shù)為N驰后,將上面式子展開:



#define metamacro_foreach_cxt_recursive(MACRO, SEP, CONTEXT, ...) \
        metamacro_foreach_cxt_recursiveN(MACRO, SEP, CONTEXT, __VA_ARGS__)

于是就轉(zhuǎn)換成了metamacro_foreach_cxt_recursiveN 宏:



#define metamacro_foreach_cxt_recursive0(MACRO, SEP, CONTEXT)
#define metamacro_foreach_cxt_recursive1(MACRO, SEP, CONTEXT, _0) MACRO(0, CONTEXT, _0)

#define metamacro_foreach_cxt_recursive2(MACRO, SEP, CONTEXT, _0, _1) \
    metamacro_foreach_cxt_recursive1(MACRO, SEP, CONTEXT, _0) \
    SEP \
    MACRO(1, CONTEXT, _1)

#define metamacro_foreach_cxt_recursive3(MACRO, SEP, CONTEXT, _0, _1, _2) \
    metamacro_foreach_cxt_recursive2(MACRO, SEP, CONTEXT, _0, _1) \
    SEP \
    MACRO(2, CONTEXT, _2)

#define metamacro_foreach_cxt_recursive4(MACRO, SEP, CONTEXT, _0, _1, _2, _3) \
    metamacro_foreach_cxt_recursive3(MACRO, SEP, CONTEXT, _0, _1, _2) \
    SEP \
    MACRO(3, CONTEXT, _3)

#define metamacro_foreach_cxt_recursive5(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4) \
    metamacro_foreach_cxt_recursive4(MACRO, SEP, CONTEXT, _0, _1, _2, _3) \
    SEP \
    MACRO(4, CONTEXT, _4)

#define metamacro_foreach_cxt_recursive6(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5) \
    metamacro_foreach_cxt_recursive5(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4) \
    SEP \
    MACRO(5, CONTEXT, _5)

#define metamacro_foreach_cxt_recursive7(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6) \
    metamacro_foreach_cxt_recursive6(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5) \
    SEP \
    MACRO(6, CONTEXT, _6)

#define metamacro_foreach_cxt_recursive8(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7) \
    metamacro_foreach_cxt_recursive7(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6) \
    SEP \
    MACRO(7, CONTEXT, _7)

#define metamacro_foreach_cxt_recursive9(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8) \
    metamacro_foreach_cxt_recursive8(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7) \
    SEP \
    MACRO(8, CONTEXT, _8)

#define metamacro_foreach_cxt_recursive10(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9) \
    metamacro_foreach_cxt_recursive9(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8) \
    SEP \
    MACRO(9, CONTEXT, _9)

#define metamacro_foreach_cxt_recursive11(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10) \
    metamacro_foreach_cxt_recursive10(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9) \
    SEP \
    MACRO(10, CONTEXT, _10)

#define metamacro_foreach_cxt_recursive12(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11) \
    metamacro_foreach_cxt_recursive11(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10) \
    SEP \
    MACRO(11, CONTEXT, _11)

#define metamacro_foreach_cxt_recursive13(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12) \
    metamacro_foreach_cxt_recursive12(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11) \
    SEP \
    MACRO(12, CONTEXT, _12)

#define metamacro_foreach_cxt_recursive14(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13) \
    metamacro_foreach_cxt_recursive13(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12) \
    SEP \
    MACRO(13, CONTEXT, _13)

#define metamacro_foreach_cxt_recursive15(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14) \
    metamacro_foreach_cxt_recursive14(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13) \
    SEP \
    MACRO(14, CONTEXT, _14)

#define metamacro_foreach_cxt_recursive16(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15) \
    metamacro_foreach_cxt_recursive15(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14) \
    SEP \
    MACRO(15, CONTEXT, _15)

#define metamacro_foreach_cxt_recursive17(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16) \
    metamacro_foreach_cxt_recursive16(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15) \
    SEP \
    MACRO(16, CONTEXT, _16)

#define metamacro_foreach_cxt_recursive18(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17) \
    metamacro_foreach_cxt_recursive17(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16) \
    SEP \
    MACRO(17, CONTEXT, _17)

#define metamacro_foreach_cxt_recursive19(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18) \
    metamacro_foreach_cxt_recursive18(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17) \
    SEP \
    MACRO(18, CONTEXT, _18)

#define metamacro_foreach_cxt_recursive20(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19) \
    metamacro_foreach_cxt_recursive19(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18) \
    SEP \
    MACRO(19, CONTEXT, _19)


提取一下metamacro_foreach_cxt_recursiveN的定義:


#define metamacro_foreach_cxt_recursiveN(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, … 肆资,_( N - 1)) \
        metamacro_foreach_cxt_recursive(N - 1)(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _( N - 2)) \
        SEP \
        MACRO(N -1, CONTEXT, _N -1)

還是按照之前分析的,同理完全展開:


    MACRO(0, CONTEXT, _0) \
    SEP \
    MACRO(1, CONTEXT, _1) \
    SEP \
    MACRO(2, CONTEXT, _2) \
    SEP \
    MACRO(3, CONTEXT, _3) \
     ……
     ……
     ……
     ……
     ……
     ……

     SEP \
    MACRO(N - 4, CONTEXT, _N - 4) \
     SEP \
    MACRO(N - 3, CONTEXT, _N - 3) \
     SEP \
    MACRO(N - 2, CONTEXT, _N - 2) \
     SEP \
    MACRO(N - 1, CONTEXT, _N - 1)



至此灶芝,展開式與metamacro_foreach_cxt(MACRO, SEP, CONTEXT, ...)宏完全相同郑原。

這個(gè)遞歸的宏從來沒有在RAC的其他宏中使用唉韭,作者在這里標(biāo)注說明了這個(gè)宏的用處。

This can be used when the former would fail due to recursive macro expansion

由于宏在遞歸展開中可能會(huì)導(dǎo)致遞歸前置條件失敗犯犁,在這種情況下属愤,應(yīng)該使用這個(gè)遞歸宏。當(dāng)然酸役,它的效果和metamacro_foreach_cxt(MACRO, SEP, CONTEXT, ...)宏是完全一樣的住诸。

6. metamacro_foreach_concat(BASE, SEP, ...)

這個(gè)宏定義是套用了metamacro_foreach_cxt(MACRO, SEP, CONTEXT, ...)宏的實(shí)現(xiàn),只是多傳入了一些參數(shù)涣澡。由此可見贱呐,metamacro_foreach_cxt(MACRO, SEP, CONTEXT, ...)宏在RAC中的重要性。


#define metamacro_foreach_concat(BASE, SEP, ...) \
        metamacro_foreach_cxt(metamacro_foreach_concat_iter, SEP, BASE, __VA_ARGS__)


由于在上面詳細(xì)分析過了metamacro_foreach_cxt(MACRO, SEP, CONTEXT, ...)宏的實(shí)現(xiàn)入桂,那么這里就直接完全展開到最后一步奄薇。MACRO = metamacro_foreach_concat_iter,SEP = SEP抗愁,CONTEXT = BASE馁蒂。


    metamacro_foreach_concat_iter(0, BASE, _0) \
    SEP \
    metamacro_foreach_concat_iter(1, BASE, _1) \
    SEP \
    metamacro_foreach_concat_iter(2, BASE, _2) \
    SEP \
    metamacro_foreach_concat_iter(3, BASE, _3) \
     ……
     ……
     ……
     ……
     ……
     ……

     SEP \
    metamacro_foreach_concat_iter(N - 4, BASE, _N - 4) \
     SEP \
    metamacro_foreach_concat_iter(N - 3, BASE, _N - 3) \
     SEP \
    metamacro_foreach_concat_iter(N - 2, BASE, _N - 2) \
     SEP \
    metamacro_foreach_concat_iter(N - 1, BASE, _N - 1)



到了這一步,就需要繼續(xù)展開metamacro_foreach_concat_iter


#define metamacro_foreach_concat_iter(INDEX, BASE, ARG) metamacro_foreach_concat_iter_(BASE, ARG)

#define metamacro_foreach_concat_iter_(BASE, ARG) BASE ## ARG


這里的2個(gè)宏蜘腌,就用到了之前說道的轉(zhuǎn)接宏的概念沫屡,因?yàn)樾枰训谝粋€(gè)參數(shù)剔除,所以需要寫一個(gè)轉(zhuǎn)接宏逢捺,轉(zhuǎn)換一次踢掉第一個(gè)參數(shù)谁鳍。

最終完全展開就是下面的樣子:


    BASE_0 \
    SEP \
    BASE_1 \
    SEP \
    BASE_2 \
    SEP \
    BASE_3 \
     ……
     ……
     ……
     ……
     ……
     ……

    SEP \
    BASE_N - 4 \
    SEP \
    BASE_N - 3 \
    SEP \
    BASE_N - 2 \
    SEP \
    BASE_N - 1



metamacro_foreach_concat(BASE, SEP, ...)宏如同它的名字一樣,把可變參數(shù)里面每個(gè)參數(shù)都拼接到BASE后面劫瞳,每個(gè)參數(shù)拼接完成之間都用SEP分隔倘潜。

試想一種場(chǎng)景:

如果有一連串的方法,方法名都有一個(gè)相同的前綴志于,后面是不同的涮因。這種場(chǎng)景下,利用metamacro_foreach_concat(BASE, SEP, ...)宏是非常爽的伺绽,它會(huì)一口氣組合出相關(guān)的一列表的不同的宏养泡。

7. metamacro_for_cxt(COUNT, MACRO, SEP, CONTEXT)

定義如下:


#define metamacro_for_cxt(COUNT, MACRO, SEP, CONTEXT) \
        metamacro_concat(metamacro_for_cxt, COUNT)(MACRO, SEP, CONTEXT)


metamacro_concat 之前分析過,展開這一層:



metamacro_for_cxtN(MACRO, SEP, CONTEXT)


metamacro_for_cxtN的定義如下:


#define metamacro_for_cxt0(MACRO, SEP, CONTEXT)
#define metamacro_for_cxt1(MACRO, SEP, CONTEXT) MACRO(0, CONTEXT)

#define metamacro_for_cxt2(MACRO, SEP, CONTEXT) \
    metamacro_for_cxt1(MACRO, SEP, CONTEXT) \
    SEP \
    MACRO(1, CONTEXT)

#define metamacro_for_cxt3(MACRO, SEP, CONTEXT) \
    metamacro_for_cxt2(MACRO, SEP, CONTEXT) \
    SEP \
    MACRO(2, CONTEXT)

#define metamacro_for_cxt4(MACRO, SEP, CONTEXT) \
    metamacro_for_cxt3(MACRO, SEP, CONTEXT) \
    SEP \
    MACRO(3, CONTEXT)

#define metamacro_for_cxt5(MACRO, SEP, CONTEXT) \
    metamacro_for_cxt4(MACRO, SEP, CONTEXT) \
    SEP \
    MACRO(4, CONTEXT)

#define metamacro_for_cxt6(MACRO, SEP, CONTEXT) \
    metamacro_for_cxt5(MACRO, SEP, CONTEXT) \
    SEP \
    MACRO(5, CONTEXT)

#define metamacro_for_cxt7(MACRO, SEP, CONTEXT) \
    metamacro_for_cxt6(MACRO, SEP, CONTEXT) \
    SEP \
    MACRO(6, CONTEXT)

#define metamacro_for_cxt8(MACRO, SEP, CONTEXT) \
    metamacro_for_cxt7(MACRO, SEP, CONTEXT) \
    SEP \
    MACRO(7, CONTEXT)

#define metamacro_for_cxt9(MACRO, SEP, CONTEXT) \
    metamacro_for_cxt8(MACRO, SEP, CONTEXT) \
    SEP \
    MACRO(8, CONTEXT)

#define metamacro_for_cxt10(MACRO, SEP, CONTEXT) \
    metamacro_for_cxt9(MACRO, SEP, CONTEXT) \
    SEP \
    MACRO(9, CONTEXT)

#define metamacro_for_cxt11(MACRO, SEP, CONTEXT) \
    metamacro_for_cxt10(MACRO, SEP, CONTEXT) \
    SEP \
    MACRO(10, CONTEXT)

#define metamacro_for_cxt12(MACRO, SEP, CONTEXT) \
    metamacro_for_cxt11(MACRO, SEP, CONTEXT) \
    SEP \
    MACRO(11, CONTEXT)

#define metamacro_for_cxt13(MACRO, SEP, CONTEXT) \
    metamacro_for_cxt12(MACRO, SEP, CONTEXT) \
    SEP \
    MACRO(12, CONTEXT)

#define metamacro_for_cxt14(MACRO, SEP, CONTEXT) \
    metamacro_for_cxt13(MACRO, SEP, CONTEXT) \
    SEP \
    MACRO(13, CONTEXT)

#define metamacro_for_cxt15(MACRO, SEP, CONTEXT) \
    metamacro_for_cxt14(MACRO, SEP, CONTEXT) \
    SEP \
    MACRO(14, CONTEXT)

#define metamacro_for_cxt16(MACRO, SEP, CONTEXT) \
    metamacro_for_cxt15(MACRO, SEP, CONTEXT) \
    SEP \
    MACRO(15, CONTEXT)

#define metamacro_for_cxt17(MACRO, SEP, CONTEXT) \
    metamacro_for_cxt16(MACRO, SEP, CONTEXT) \
    SEP \
    MACRO(16, CONTEXT)

#define metamacro_for_cxt18(MACRO, SEP, CONTEXT) \
    metamacro_for_cxt17(MACRO, SEP, CONTEXT) \
    SEP \
    MACRO(17, CONTEXT)

#define metamacro_for_cxt19(MACRO, SEP, CONTEXT) \
    metamacro_for_cxt18(MACRO, SEP, CONTEXT) \
    SEP \
    MACRO(18, CONTEXT)

#define metamacro_for_cxt20(MACRO, SEP, CONTEXT) \
    metamacro_for_cxt19(MACRO, SEP, CONTEXT) \
    SEP \
    MACRO(19, CONTEXT)



提取一下metamacro_for_cxtN的定義:



#define metamacro_for_cxtN(MACRO, SEP, CONTEXT) \
        metamacro_for_cxtN - 1(MACRO, SEP, CONTEXT) \
        SEP \
        MACRO(N - 1, CONTEXT)

把metamacro_for_cxtN完全展開如下:



    MACRO(0, CONTEXT) \
    SEP \
    MACRO(1, CONTEXT) \
    SEP \
    MACRO(2, CONTEXT) \
    SEP \
    MACRO(3, CONTEXT) \
     ……
     ……
     ……
     ……
     ……
     ……

     SEP \
    MACRO(N - 4, CONTEXT) \
     SEP \
    MACRO(N - 3, CONTEXT) \
     SEP \
    MACRO(N - 2, CONTEXT) \
     SEP \
    MACRO(N - 1, CONTEXT)


這個(gè)宏的用途是執(zhí)行COUNT次MACRO宏命令奈应,每次MACRO宏命令的第一個(gè)參數(shù)都會(huì)從COUNT開始遞減到0澜掩。

8. metamacro_head(...)

這個(gè)宏要求它的可變參數(shù)至少為1個(gè)。


#define metamacro_head(...) \
        metamacro_head_(__VA_ARGS__, 0)


把宏展開杖挣,如下:


#define metamacro_head_(FIRST, ...) FIRST


metamacro_head(...) 的作用就是取出可變參數(shù)列表的第一個(gè)參數(shù)肩榕。

9. metamacro_tail(...)

這個(gè)宏要求它的可變參數(shù)至少為2個(gè)。


#define metamacro_tail(...) \
        metamacro_tail_(__VA_ARGS__)


把宏展開惩妇,如下:


#define metamacro_tail_(FIRST, ...) __VA_ARGS__


metamacro_tail(...) 的作用就是取出可變參數(shù)列表除去第一個(gè)參數(shù)以外的所有參數(shù)株汉。

10. metamacro_take(N, ...)

這個(gè)宏要求它的可變參數(shù)至少有N個(gè)筐乳。



#define metamacro_take(N, ...) \
        metamacro_concat(metamacro_take, N)(__VA_ARGS__)

展開成如下的樣子:



metamacro_takeN(__VA_ARGS__)

繼續(xù)展開metamacro_takeN:


#define metamacro_take0(...)
#define metamacro_take1(...) metamacro_head(__VA_ARGS__)
#define metamacro_take2(...) metamacro_head(__VA_ARGS__), metamacro_take1(metamacro_tail(__VA_ARGS__))
#define metamacro_take3(...) metamacro_head(__VA_ARGS__), metamacro_take2(metamacro_tail(__VA_ARGS__))
#define metamacro_take4(...) metamacro_head(__VA_ARGS__), metamacro_take3(metamacro_tail(__VA_ARGS__))
#define metamacro_take5(...) metamacro_head(__VA_ARGS__), metamacro_take4(metamacro_tail(__VA_ARGS__))
#define metamacro_take6(...) metamacro_head(__VA_ARGS__), metamacro_take5(metamacro_tail(__VA_ARGS__))
#define metamacro_take7(...) metamacro_head(__VA_ARGS__), metamacro_take6(metamacro_tail(__VA_ARGS__))
#define metamacro_take8(...) metamacro_head(__VA_ARGS__), metamacro_take7(metamacro_tail(__VA_ARGS__))
#define metamacro_take9(...) metamacro_head(__VA_ARGS__), metamacro_take8(metamacro_tail(__VA_ARGS__))
#define metamacro_take10(...) metamacro_head(__VA_ARGS__), metamacro_take9(metamacro_tail(__VA_ARGS__))
#define metamacro_take11(...) metamacro_head(__VA_ARGS__), metamacro_take10(metamacro_tail(__VA_ARGS__))
#define metamacro_take12(...) metamacro_head(__VA_ARGS__), metamacro_take11(metamacro_tail(__VA_ARGS__))
#define metamacro_take13(...) metamacro_head(__VA_ARGS__), metamacro_take12(metamacro_tail(__VA_ARGS__))
#define metamacro_take14(...) metamacro_head(__VA_ARGS__), metamacro_take13(metamacro_tail(__VA_ARGS__))
#define metamacro_take15(...) metamacro_head(__VA_ARGS__), metamacro_take14(metamacro_tail(__VA_ARGS__))
#define metamacro_take16(...) metamacro_head(__VA_ARGS__), metamacro_take15(metamacro_tail(__VA_ARGS__))
#define metamacro_take17(...) metamacro_head(__VA_ARGS__), metamacro_take16(metamacro_tail(__VA_ARGS__))
#define metamacro_take18(...) metamacro_head(__VA_ARGS__), metamacro_take17(metamacro_tail(__VA_ARGS__))
#define metamacro_take19(...) metamacro_head(__VA_ARGS__), metamacro_take18(metamacro_tail(__VA_ARGS__))
#define metamacro_take20(...) metamacro_head(__VA_ARGS__), metamacro_take19(metamacro_tail(__VA_ARGS__))


這里也用到了遞歸的思想,每次取完頭以后乔妈,剩下的隊(duì)列針對(duì)于此次是tail蝙云,對(duì)于下次是head。所以每次都取head路召,之后再遞歸的取剩下部分的head勃刨,直到取出前N個(gè)數(shù)為止。

metamacro_take(N, ...)的作用就是取出可變參數(shù)的前N個(gè)數(shù)优训,并把它們組合成新的參數(shù)列表朵你。

11. metamacro_drop(N, ...)

這個(gè)宏要求它的可變參數(shù)至少為N個(gè)。


#define metamacro_drop(N, ...) \
        metamacro_concat(metamacro_drop, N)(__VA_ARGS__)

展開成如下的樣子:



metamacro_dropN(__VA_ARGS__)

繼續(xù)展開metamacro_dropN:



#define metamacro_drop0(...) __VA_ARGS__
#define metamacro_drop1(...) metamacro_tail(__VA_ARGS__)
#define metamacro_drop2(...) metamacro_drop1(metamacro_tail(__VA_ARGS__))
#define metamacro_drop3(...) metamacro_drop2(metamacro_tail(__VA_ARGS__))
#define metamacro_drop4(...) metamacro_drop3(metamacro_tail(__VA_ARGS__))
#define metamacro_drop5(...) metamacro_drop4(metamacro_tail(__VA_ARGS__))
#define metamacro_drop6(...) metamacro_drop5(metamacro_tail(__VA_ARGS__))
#define metamacro_drop7(...) metamacro_drop6(metamacro_tail(__VA_ARGS__))
#define metamacro_drop8(...) metamacro_drop7(metamacro_tail(__VA_ARGS__))
#define metamacro_drop9(...) metamacro_drop8(metamacro_tail(__VA_ARGS__))
#define metamacro_drop10(...) metamacro_drop9(metamacro_tail(__VA_ARGS__))
#define metamacro_drop11(...) metamacro_drop10(metamacro_tail(__VA_ARGS__))
#define metamacro_drop12(...) metamacro_drop11(metamacro_tail(__VA_ARGS__))
#define metamacro_drop13(...) metamacro_drop12(metamacro_tail(__VA_ARGS__))
#define metamacro_drop14(...) metamacro_drop13(metamacro_tail(__VA_ARGS__))
#define metamacro_drop15(...) metamacro_drop14(metamacro_tail(__VA_ARGS__))
#define metamacro_drop16(...) metamacro_drop15(metamacro_tail(__VA_ARGS__))
#define metamacro_drop17(...) metamacro_drop16(metamacro_tail(__VA_ARGS__))
#define metamacro_drop18(...) metamacro_drop17(metamacro_tail(__VA_ARGS__))
#define metamacro_drop19(...) metamacro_drop18(metamacro_tail(__VA_ARGS__))
#define metamacro_drop20(...) metamacro_drop19(metamacro_tail(__VA_ARGS__))


這里也用到了遞歸的思想揣非,每次都取當(dāng)前隊(duì)列的tail抡医,每次都丟掉當(dāng)前隊(duì)列的head。這樣遞歸N次就丟掉了前N位參數(shù)早敬。

metamacro_drop(N, ...)的作用是丟掉當(dāng)前參數(shù)列表里面的前N位參數(shù)忌傻。

12. metamacro_dec(VAL) 和 metamacro_inc(VAL)

這兩個(gè)宏是一對(duì)。它們?cè)谠幊讨懈慵啵幚碛?jì)數(shù)和index方面及其有用水孩。VAL的值域都是[0,20]。


#define metamacro_dec(VAL) \
        metamacro_at(VAL, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19)



metamacro_dec(VAL) 提供了一個(gè)被左移一位的[0,20]的序列琐驴。那么通過metamacro_at計(jì)算出來的結(jié)果就比原來的結(jié)果小1俘种。從而達(dá)到了減一的目的。


#define metamacro_inc(VAL) \
        metamacro_at(VAL, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21)


metamacro_inc(VAL) 提供了一個(gè)被右移一位的[0,20]的序列绝淡。那么通過metamacro_at計(jì)算出來的結(jié)果就比原來的結(jié)果大1宙刘。從而達(dá)到了加一的目的。

13. metamacro_if_eq(A, B)

首先A 和 B的值域都為[0,20]牢酵,并且B要大于等于A悬包,即0<=A<=B<=20。


#define metamacro_if_eq(A, B) \
        metamacro_concat(metamacro_if_eq, A)(B)


如果當(dāng)A不等于0的時(shí)候馍乙,將上面的式子展開:



#define metamacro_if_eq(A, B) \
        metamacro_if_eqA(B)


再繼續(xù)把metamacro_if_eqA展開:



#define metamacro_if_eq1(VALUE) metamacro_if_eq0(metamacro_dec(VALUE))
#define metamacro_if_eq2(VALUE) metamacro_if_eq1(metamacro_dec(VALUE))
#define metamacro_if_eq3(VALUE) metamacro_if_eq2(metamacro_dec(VALUE))
#define metamacro_if_eq4(VALUE) metamacro_if_eq3(metamacro_dec(VALUE))
#define metamacro_if_eq5(VALUE) metamacro_if_eq4(metamacro_dec(VALUE))
#define metamacro_if_eq6(VALUE) metamacro_if_eq5(metamacro_dec(VALUE))
#define metamacro_if_eq7(VALUE) metamacro_if_eq6(metamacro_dec(VALUE))
#define metamacro_if_eq8(VALUE) metamacro_if_eq7(metamacro_dec(VALUE))
#define metamacro_if_eq9(VALUE) metamacro_if_eq8(metamacro_dec(VALUE))
#define metamacro_if_eq10(VALUE) metamacro_if_eq9(metamacro_dec(VALUE))
#define metamacro_if_eq11(VALUE) metamacro_if_eq10(metamacro_dec(VALUE))
#define metamacro_if_eq12(VALUE) metamacro_if_eq11(metamacro_dec(VALUE))
#define metamacro_if_eq13(VALUE) metamacro_if_eq12(metamacro_dec(VALUE))
#define metamacro_if_eq14(VALUE) metamacro_if_eq13(metamacro_dec(VALUE))
#define metamacro_if_eq15(VALUE) metamacro_if_eq14(metamacro_dec(VALUE))
#define metamacro_if_eq16(VALUE) metamacro_if_eq15(metamacro_dec(VALUE))
#define metamacro_if_eq17(VALUE) metamacro_if_eq16(metamacro_dec(VALUE))
#define metamacro_if_eq18(VALUE) metamacro_if_eq17(metamacro_dec(VALUE))
#define metamacro_if_eq19(VALUE) metamacro_if_eq18(metamacro_dec(VALUE))
#define metamacro_if_eq20(VALUE) metamacro_if_eq19(metamacro_dec(VALUE))


上面是一個(gè)遞推的式子布近,最終肯定會(huì)得到metamacro_if_eq0,最終的結(jié)果就是:



metamacro_if_eq0(B - A)


再把metamacro_if_eq0展開:


#define metamacro_if_eq0(VALUE) \
        metamacro_concat(metamacro_if_eq0_, VALUE)


得到最終的展開式子:



metamacro_if_eq0_(B - A)

再查表得到最終結(jié)果:



#define metamacro_if_eq0_0(...) __VA_ARGS__ metamacro_consume_
#define metamacro_if_eq0_1(...) metamacro_expand_
#define metamacro_if_eq0_2(...) metamacro_expand_
#define metamacro_if_eq0_3(...) metamacro_expand_
#define metamacro_if_eq0_4(...) metamacro_expand_
#define metamacro_if_eq0_5(...) metamacro_expand_
#define metamacro_if_eq0_6(...) metamacro_expand_
#define metamacro_if_eq0_7(...) metamacro_expand_
#define metamacro_if_eq0_8(...) metamacro_expand_
#define metamacro_if_eq0_9(...) metamacro_expand_
#define metamacro_if_eq0_10(...) metamacro_expand_
#define metamacro_if_eq0_11(...) metamacro_expand_
#define metamacro_if_eq0_12(...) metamacro_expand_
#define metamacro_if_eq0_13(...) metamacro_expand_
#define metamacro_if_eq0_14(...) metamacro_expand_
#define metamacro_if_eq0_15(...) metamacro_expand_
#define metamacro_if_eq0_16(...) metamacro_expand_
#define metamacro_if_eq0_17(...) metamacro_expand_
#define metamacro_if_eq0_18(...) metamacro_expand_
#define metamacro_if_eq0_19(...) metamacro_expand_
#define metamacro_if_eq0_20(...) metamacro_expand_

上面這張表有兩點(diǎn)注意點(diǎn):

  1. 除了0_0丝格,其他的都是metamacro_expand_撑瞧。

#define metamacro_consume_(...)
#define metamacro_expand_(...) __VA_ARGS__


除了0_0以外,其他所有操作都是直接透?jìng)鲄?shù)显蝌,什么也不處理季蚂。metamacro_consume_(...)就是直接吞掉后續(xù)的參數(shù)。expand就是指的是可以繼續(xù)展開宏琅束,consume就是指的是終止展開宏扭屁,并吃掉后面的參數(shù)。

舉2個(gè)例子:


// 第一個(gè)例子
metamacro_if_eq(0, 0)(true)(false)

// 第二個(gè)例子
metamacro_if_eq(0, 1)(true)(false)



直接套用最終展開式:


// 第一個(gè)例子
metamacro_if_eq0_0(true)(false)

// 第二個(gè)例子
metamacro_if_eq0_1(true)(false)


繼續(xù)展開:


// 第一個(gè)例子
true metamacro_consume_(false) => true

// 第二個(gè)例子
metamacro_expand_(false) => false


這個(gè)如果 B < A涩禀,那么(B - A) < 0料滥,那么最終展開的式子就變成下面的樣子:



metamacro_if_eq0_(負(fù)數(shù))


這個(gè)宏展開到這個(gè)程度就沒法繼續(xù)下去了,就會(huì)出現(xiàn)編譯錯(cuò)誤艾船。

14. metamacro_if_eq_recursive(A, B)

A 和 B的值域都為[0,20]葵腹,并且B要大于等于A,即0<=A<=B<=20屿岂。

定義如下:



#define metamacro_if_eq_recursive(A, B) \
        metamacro_concat(metamacro_if_eq_recursive, A)(B)


展開之后:


metamacro_if_eq_recursiveA(B)

繼續(xù)展開:


#define metamacro_if_eq_recursive1(VALUE) metamacro_if_eq_recursive0(metamacro_dec(VALUE))
#define metamacro_if_eq_recursive2(VALUE) metamacro_if_eq_recursive1(metamacro_dec(VALUE))
#define metamacro_if_eq_recursive3(VALUE) metamacro_if_eq_recursive2(metamacro_dec(VALUE))
#define metamacro_if_eq_recursive4(VALUE) metamacro_if_eq_recursive3(metamacro_dec(VALUE))
#define metamacro_if_eq_recursive5(VALUE) metamacro_if_eq_recursive4(metamacro_dec(VALUE))
#define metamacro_if_eq_recursive6(VALUE) metamacro_if_eq_recursive5(metamacro_dec(VALUE))
#define metamacro_if_eq_recursive7(VALUE) metamacro_if_eq_recursive6(metamacro_dec(VALUE))
#define metamacro_if_eq_recursive8(VALUE) metamacro_if_eq_recursive7(metamacro_dec(VALUE))
#define metamacro_if_eq_recursive9(VALUE) metamacro_if_eq_recursive8(metamacro_dec(VALUE))
#define metamacro_if_eq_recursive10(VALUE) metamacro_if_eq_recursive9(metamacro_dec(VALUE))
#define metamacro_if_eq_recursive11(VALUE) metamacro_if_eq_recursive10(metamacro_dec(VALUE))
#define metamacro_if_eq_recursive12(VALUE) metamacro_if_eq_recursive11(metamacro_dec(VALUE))
#define metamacro_if_eq_recursive13(VALUE) metamacro_if_eq_recursive12(metamacro_dec(VALUE))
#define metamacro_if_eq_recursive14(VALUE) metamacro_if_eq_recursive13(metamacro_dec(VALUE))
#define metamacro_if_eq_recursive15(VALUE) metamacro_if_eq_recursive14(metamacro_dec(VALUE))
#define metamacro_if_eq_recursive16(VALUE) metamacro_if_eq_recursive15(metamacro_dec(VALUE))
#define metamacro_if_eq_recursive17(VALUE) metamacro_if_eq_recursive16(metamacro_dec(VALUE))
#define metamacro_if_eq_recursive18(VALUE) metamacro_if_eq_recursive17(metamacro_dec(VALUE))
#define metamacro_if_eq_recursive19(VALUE) metamacro_if_eq_recursive18(metamacro_dec(VALUE))
#define metamacro_if_eq_recursive20(VALUE) metamacro_if_eq_recursive19(metamacro_dec(VALUE))



最終肯定會(huì)得到metamacro_if_eq_recursive0_践宴,最終的結(jié)果就是:



metamacro_if_eq_recursive0_(B - A)


再把metamacro_if_eq_recursive0_展開:



#define metamacro_if_eq_recursive0(VALUE) \
    metamacro_concat(metamacro_if_eq_recursive0_, VALUE)


得到最終的式子:



metamacro_if_eq_recursive0_(B - A)


最終再比對(duì)下表:



#define metamacro_if_eq_recursive0_0(...) __VA_ARGS__ metamacro_consume_
#define metamacro_if_eq_recursive0_1(...) metamacro_expand_
#define metamacro_if_eq_recursive0_2(...) metamacro_expand_
#define metamacro_if_eq_recursive0_3(...) metamacro_expand_
#define metamacro_if_eq_recursive0_4(...) metamacro_expand_
#define metamacro_if_eq_recursive0_5(...) metamacro_expand_
#define metamacro_if_eq_recursive0_6(...) metamacro_expand_
#define metamacro_if_eq_recursive0_7(...) metamacro_expand_
#define metamacro_if_eq_recursive0_8(...) metamacro_expand_
#define metamacro_if_eq_recursive0_9(...) metamacro_expand_
#define metamacro_if_eq_recursive0_10(...) metamacro_expand_
#define metamacro_if_eq_recursive0_11(...) metamacro_expand_
#define metamacro_if_eq_recursive0_12(...) metamacro_expand_
#define metamacro_if_eq_recursive0_13(...) metamacro_expand_
#define metamacro_if_eq_recursive0_14(...) metamacro_expand_
#define metamacro_if_eq_recursive0_15(...) metamacro_expand_
#define metamacro_if_eq_recursive0_16(...) metamacro_expand_
#define metamacro_if_eq_recursive0_17(...) metamacro_expand_
#define metamacro_if_eq_recursive0_18(...) metamacro_expand_
#define metamacro_if_eq_recursive0_19(...) metamacro_expand_
#define metamacro_if_eq_recursive0_20(...) metamacro_expand_


接下來就和metamacro_if_eq(A, B)宏完全一樣了。

這個(gè)遞歸的宏也從來沒有在RAC的其他宏中使用爷怀,作者在這里標(biāo)注說明了這個(gè)宏的用處阻肩。

This can be used when the former would fail due to recursive macro expansion

由于宏在遞歸展開中可能會(huì)導(dǎo)致遞歸前置條件失敗褂痰,在這種情況下碟绑,應(yīng)該使用這個(gè)遞歸宏。當(dāng)然熙侍,它的效果和metamacro_if_eq(A, B)宏是完全一樣的吁朦。

15. metamacro_is_even(N)

定義如下:

N的值域在[0,20]之間柒室。


#define metamacro_is_even(N) \
        metamacro_at(N, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1)



這個(gè)宏比較簡(jiǎn)單,就是判斷N是不是偶數(shù)逗宜,下面metamacro_at把所有從0-20的自然數(shù)是偶數(shù)的都標(biāo)志成了1雄右,是奇數(shù)的都標(biāo)志成了0。0在這里默認(rèn)是偶數(shù)纺讲。

16. metamacro_not(B)

這里B的取值只能是0或者1擂仍。



#define metamacro_not(B) \
        metamacro_at(B, 1, 0)


這個(gè)宏很簡(jiǎn)單,就是對(duì)參數(shù)邏輯取非運(yùn)算刻诊。

三. ReactiveCocoa 中常用的宏

上一章節(jié)我們分析完了ReactiveCocoa中所有的元宏防楷,這一章節(jié)將會(huì)把元宏以外的宏的實(shí)現(xiàn)都分析一遍。包括我們?nèi)粘J褂玫某R姷乃泻暝蜓模鼈兛此粕衩馗淳郑撬麄兌际怯蛇@些元宏來組成的。

1. weakify(...)粟判、unsafeify(...)亿昏、strongify(...)

這三個(gè)在ReactiveCocoa一定是使用最多的,那么就先來分析這三個(gè)档礁。這三個(gè)宏的定義在RACEXTScope.h中角钩。

關(guān)于weakify(...)和strongify(...),這兩個(gè)宏的實(shí)現(xiàn)分析在之前的文章里面詳細(xì)分析過了,詳情可以看這篇文章《深入研究Block用weakSelf递礼、strongSelf惨险、@weakify、@strongify解決循環(huán)引用》脊髓。

這里需要再次強(qiáng)調(diào)的一點(diǎn)是辫愉,在使用weakify(...)、unsafeify(...)将硝、strongify(...)這三個(gè)宏的前面需要額外添加@符號(hào)恭朗。原因是在這三個(gè)宏的實(shí)現(xiàn)里面都有rac_keywordify,它的實(shí)現(xiàn)如下:


#if DEBUG
#define rac_keywordify autoreleasepool {}
#else
#define rac_keywordify try {} @catch (...) {}
#endif


不管是在什么環(huán)境下依疼,autoreleasepool {} 和 try {} @catch (...) {} 前面都要添加@符號(hào)痰腮,變成@autoreleasepool {} 和 @try {} @catch (...) {} 才可以繼續(xù)使用。

既然@weakify(...)律罢,@strongify(...)都分析過了膀值,那么這里就分析一下@unsafeify(...)的實(shí)現(xiàn)。


#define unsafeify(...) \
        rac_keywordify \
        metamacro_foreach_cxt(rac_weakify_,, __unsafe_unretained, __VA_ARGS__)



rac_keywordify上面說過了弟翘,這里就直接展開metamacro_foreach_cxt宏虫腋。這里就套用之前元宏的分析,直接拿到最終展開表達(dá)式:


    MACRO(0, CONTEXT, _0) \
    SEP \
    MACRO(1, CONTEXT, _1) \
    SEP \
    MACRO(2, CONTEXT, _2) \
    SEP \
    MACRO(3, CONTEXT, _3) \
     ……
     ……
     ……
     ……
     ……
     ……

     SEP \
    MACRO(N - 4, CONTEXT, _N - 4) \
     SEP \
    MACRO(N - 3, CONTEXT, _N - 3) \
     SEP \
    MACRO(N - 2, CONTEXT, _N - 2) \
     SEP \
    MACRO(N - 1, CONTEXT, _N - 1)

MACRO = rac_weakify_稀余,SEP = 空格悦冀,CONTEXT = __unsafe_unretained。代入得到最終的展開式:



    rac_weakify_(0,  __unsafe_unretained, _0) \
    rac_weakify_(1,  __unsafe_unretained, _1) \
    rac_weakify_(2,  __unsafe_unretained, _2) \
    rac_weakify_(3,  __unsafe_unretained, _3) \
     ……
     ……
     ……
     ……
     ……
     ……

    rac_weakify_(N - 4,  __unsafe_unretained, _N - 4) \
    rac_weakify_(N - 3,  __unsafe_unretained, _N - 3) \
    rac_weakify_(N - 2,  __unsafe_unretained, _N - 2) \
    rac_weakify_(N - 1,  __unsafe_unretained, _N - 1)

把rac_weakify_再替換掉:


#define rac_weakify_(INDEX, CONTEXT, VAR) \
    CONTEXT __typeof__(VAR) metamacro_concat(VAR, _weak_) = (VAR);


得到最終的展開表達(dá)式:



__unsafe_unretained  __typeof__(_0) _0_weak_ = _0睛琳;
__unsafe_unretained  __typeof__(_1) _1_weak_ = _1盒蟆;
__unsafe_unretained  __typeof__(_2) _2_weak_ = _2;
     ……
     ……
     ……
     ……
     ……
     ……
__unsafe_unretained  __typeof__(_N - 3) _N - 3_weak_ = _N - 3师骗;
__unsafe_unretained  __typeof__(_N - 2) _N - 2_weak_ = _N - 2历等;
__unsafe_unretained  __typeof__(_N - 1) _N - 1_weak_ = _N - 1;



其中 _0辟癌, _1寒屯, _2 …… _N - 3, _N - 2黍少, _N - 1是 __VA_ARGS__里面對(duì)應(yīng)的是0 - N的參數(shù)值寡夹。

2. RACTuplePack(...) 和 RACTupleUnpack(...)

這兩個(gè)在ReactiveCocoa中也是非常常見的宏,專門用在RACTuple中厂置。

先看RACTuplePack(...)


#define RACTuplePack(...) \
        RACTuplePack_(__VA_ARGS__)

再展開一步:


#define RACTuplePack_(...) \
        ([RACTuple tupleWithObjectsFromArray:@[ metamacro_foreach(RACTuplePack_object_or_ractuplenil,, __VA_ARGS__) ]])


這里調(diào)用了RACTuple的tupleWithObjectsFromArray:方法菩掏。主要需要展開的是:


metamacro_foreach(RACTuplePack_object_or_ractuplenil,, __VA_ARGS__) 


直接調(diào)用上一章節(jié)中metamacro_foreach的最終表達(dá)式:



    MACRO(0, _0) \
    SEP \
    MACRO(1, _1) \
    SEP \
    MACRO(2, _2) \
    SEP \
    MACRO(3, _3) \
     ……
     ……
     ……
     ……
     ……
     ……

     SEP \
    MACRO(N - 4, _N - 4) \
     SEP \
    MACRO(N - 3, _N - 3) \
     SEP \
    MACRO(N - 2, _N - 2) \
     SEP \
    MACRO(N - 1, _N - 1)



MACRO = RACTuplePack_object_or_ractuplenil , SEP = 空格昵济,替換之后如下:


RACTuplePack_object_or_ractuplenil(0, _0) \
RACTuplePack_object_or_ractuplenil(1, _1) \
RACTuplePack_object_or_ractuplenil(2, _2) \
     ……
     ……
     ……
     ……
     ……
     ……
RACTuplePack_object_or_ractuplenil( N - 3, _N - 3) \
RACTuplePack_object_or_ractuplenil( N - 2, _N - 2) \
RACTuplePack_object_or_ractuplenil( N - 1, _N - 1) 

最后一步就是替換掉RACTuplePack_object_or_ractuplenil:


#define RACTuplePack_object_or_ractuplenil(INDEX, ARG) \
    (ARG) ?: RACTupleNil.tupleNil,

注意這里宏結(jié)尾是“智绸,”逗號(hào)野揪,而不是“;”分號(hào)瞧栗,原因是因?yàn)閠upleWithObjectsFromArray:方法里面是各個(gè)元素斯稳,所以這里用“;”分號(hào)就會(huì)出錯(cuò)沼溜,反而應(yīng)該用“平挑,”逗號(hào),可見設(shè)計(jì)宏的時(shí)候需要考慮清楚使用場(chǎng)景系草,不能亂寫。

展開上面最后一層宏之后唆涝,原可變參數(shù)列表里面的所有非nil的值就都排列到了tupleWithObjectsFromArray:方法里面了找都,如果是nil的,就會(huì)變成RACTupleNil.tupleNil放進(jìn)Array里面廊酣。

再來看看RACTupleUnpack(...)


#define RACTupleUnpack(...) \
        RACTupleUnpack_(__VA_ARGS__)


再展開一步:


#define RACTupleUnpack_(...) \
    metamacro_foreach(RACTupleUnpack_decl,, __VA_ARGS__) \
    \
    int RACTupleUnpack_state = 0; \
    \
    RACTupleUnpack_after: \
        ; \
        metamacro_foreach(RACTupleUnpack_assign,, __VA_ARGS__) \
        if (RACTupleUnpack_state != 0) RACTupleUnpack_state = 2; \
        \
        while (RACTupleUnpack_state != 2) \
            if (RACTupleUnpack_state == 1) { \
                goto RACTupleUnpack_after; \
            } else \
                for (; RACTupleUnpack_state != 1; RACTupleUnpack_state = 1) \
                    [RACTupleUnpackingTrampoline trampoline][ @[ metamacro_foreach(RACTupleUnpack_value,, __VA_ARGS__) ] ]



乍一看這個(gè)宏像一段程序能耻,仔細(xì)分析一下也不難。RACTupleUnpack_state 就是一個(gè)局部變量亡驰,代表狀態(tài)的晓猛。RACTupleUnpack_after: 這是一個(gè)標(biāo)號(hào),用來給goto跳轉(zhuǎn)使用的凡辱。


// 1
metamacro_foreach(RACTupleUnpack_decl,, __VA_ARGS__) 
// 2
metamacro_foreach(RACTupleUnpack_assign,, __VA_ARGS__)
// 3
metamacro_foreach(RACTupleUnpack_value,, __VA_ARGS__)

這里面需要展開的就是這3個(gè)宏了戒职。

套用上一章節(jié)中metamacro_foreach的最終表達(dá)式,直接把MACRO分別為 RACTupleUnpack_decl透乾,RACTupleUnpack_assign洪燥,RACTupleUnpack_value 代入表達(dá)式。


// 1
RACTupleUnpack_decl(0, _0) \
     ……
     ……
     ……
RACTupleUnpack_decl( N - 1, _N - 1)
// 2
RACTupleUnpack_assign(0, _0) \
     ……
     ……
     ……
RACTupleUnpack_assign( N - 1, _N - 1)
// 3
RACTupleUnpack_value(0, _0) \
     ……
     ……
     ……
RACTupleUnpack_value( N - 1, _N - 1)


分別替換掉這3個(gè)宏:


#define RACTupleUnpack_decl(INDEX, ARG) \
    __strong id RACTupleUnpack_decl_name(INDEX);

#define RACTupleUnpack_assign(INDEX, ARG) \
    __strong ARG = RACTupleUnpack_decl_name(INDEX);

#define RACTupleUnpack_value(INDEX, ARG) \
    [NSValue valueWithPointer:&RACTupleUnpack_decl_name(INDEX)],



發(fā)現(xiàn)這3個(gè)宏都是用RACTupleUnpack_decl_name實(shí)現(xiàn)的乳乌。


#define RACTupleUnpack_decl_name(INDEX) \
        metamacro_concat(metamacro_concat(RACTupleUnpack, __LINE__), metamacro_concat(_var, INDEX))



這個(gè)展開就是一個(gè)名字:


RACTupleUnpack __LINE__ _varINDEX

之后的實(shí)現(xiàn)捧韵,請(qǐng)看《ReactiveCocoa 中 集合類RACSequence 和 RACTuple底層實(shí)現(xiàn)分析》這篇文章的詳細(xì)分析。

3. RACObserve(TARGET, KEYPATH)

定義如下:


#define RACObserve(TARGET, KEYPATH) \
    ({ \
        _Pragma("clang diagnostic push") \
        _Pragma("clang diagnostic ignored \"-Wreceiver-is-weak\"") \
        __weak id target_ = (TARGET); \
        [target_ rac_valuesForKeyPath:@keypath(TARGET, KEYPATH) observer:self]; \
        _Pragma("clang diagnostic pop") \
    })


看完定義汉操,RACObserve(TARGET, KEYPATH) 實(shí)質(zhì)其實(shí)就是調(diào)用了rac_valuesForKeyPath:方法再来。這個(gè)方法是NSObject的一個(gè)category,所以只要是NSObject就可以調(diào)用這個(gè)方法磷瘤。所以這里的關(guān)鍵就是要分析清楚@keypath(TARGET, KEYPATH) 這個(gè)宏的實(shí)現(xiàn)芒篷。

以下重點(diǎn)分析一下keypath(...)的實(shí)現(xiàn)


#define keypath(...) \
    metamacro_if_eq(1, metamacro_argcount(__VA_ARGS__))(keypath1(__VA_ARGS__))(keypath2(__VA_ARGS__))

#define keypath1(PATH) \
    (((void)(NO && ((void)PATH, NO)), strchr(# PATH, '.') + 1))

#define keypath2(OBJ, PATH) \
    (((void)(NO && ((void)OBJ.PATH, NO)), # PATH))



metamacro_argcount這個(gè)宏在元宏里面分析過,是取出可變參數(shù)個(gè)數(shù)的膀斋。metamacro_if_eq也詳細(xì)分析過梭伐,是判斷里面2個(gè)參數(shù)是否相當(dāng)?shù)摹K詋eypath(...)總體展開的意思是說仰担,可變參數(shù)的個(gè)數(shù)是否等于1糊识,如果等于1绩社,就執(zhí)行(keypath1(__VA_ARGS__)),如果不等于1赂苗,就執(zhí)行(keypath2(__VA_ARGS__))愉耙。

這里有幾點(diǎn)需要說明的:

1.加void是為了防止逗號(hào)表達(dá)式的warning。例如:


int a=0; int b = 1;
int c = (a,b);


由于a沒有被用到拌滋,所以會(huì)有警告朴沿。但是寫成如下的樣子就不會(huì)出現(xiàn)警告了:


int c = ((void)a,b);


所以上面keypath1和keypath2加了幾個(gè)void就是為了防止出現(xiàn)warning。

2.加NO是C語言判斷條件短路表達(dá)式败砂。增加NO && 以后赌渣,預(yù)編譯的時(shí)候看見了NO,就會(huì)很快的跳過判斷條件昌犹。

3.strchr函數(shù)原型如下:


extern char *strchr(const char *s,char c);

查找字符串s中首次出現(xiàn)字符c的位置坚芜。返回首次出現(xiàn)字符c的位置的指針,返回的地址是被查找字符串指針開始的第一個(gè)與字符c相同字符的指針斜姥,如果字符串中不存在字符c則返回NULL鸿竖。

4.當(dāng)輸入self.的時(shí)候,會(huì)出現(xiàn)編譯器的語法提示铸敏,原因是OBJ.PATH缚忧,因?yàn)檫@里的點(diǎn),所以輸入第二個(gè)參數(shù)時(shí)編輯器會(huì)給出正確的代碼提示杈笔。

5.使用keypath(...)的時(shí)候前面會(huì)加上@符號(hào)闪水,原因是經(jīng)過keypath1(PATH)和keypath2(OBJ, PATH)之后出現(xiàn)的結(jié)果是一個(gè)C的字符串,前面加上@以后桩撮,就變成了OC的字符串了敦第。

舉3個(gè)例子




// 例子1,一個(gè)參數(shù)的情況店量,會(huì)調(diào)用keypath1(PATH)
NSString *UTF8StringPath = @keypath(str.lowercaseString.UTF8String);
// 輸出=> @"lowercaseString.UTF8String"


// 例子2芜果,2個(gè)參數(shù)的情況,支持自省
NSString *versionPath = @keypath(NSObject, version);
//  輸出=> @"version"

// 例子3融师,2個(gè)參數(shù)的情況
NSString *lowercaseStringPath = @keypath(NSString.new, lowercaseString);
// 輸出=> @"lowercaseString"


相應(yīng)的也有集合類的keypath


#define collectionKeypath(...) \
    metamacro_if_eq(3, metamacro_argcount(__VA_ARGS__))(collectionKeypath3(__VA_ARGS__))(collectionKeypath4(__VA_ARGS__))

#define collectionKeypath3(PATH, COLLECTION_OBJECT, COLLECTION_PATH) ([[NSString stringWithFormat:@"%s.%s",keypath(PATH), keypath(COLLECTION_OBJECT, COLLECTION_PATH)] UTF8String])

#define collectionKeypath4(OBJ, PATH, COLLECTION_OBJECT, COLLECTION_PATH) ([[NSString stringWithFormat:@"%s.%s",keypath(OBJ, PATH), keypath(COLLECTION_OBJECT, COLLECTION_PATH)] UTF8String])


原理也是調(diào)用了keypath(PATH)右钾,原理這里就不再贅述了。

4. RAC(TARGET, ...)

宏定義如下:


#define RAC(TARGET, ...) \
        metamacro_if_eq(1, metamacro_argcount(__VA_ARGS__)) \
        (RAC_(TARGET, __VA_ARGS__, nil)) \
        (RAC_(TARGET, __VA_ARGS__))


RAC(TARGET, ...) 和上一個(gè)RACObserve(TARGET, KEYPATH)原理類似旱爆。如果只有一個(gè)參數(shù)就調(diào)用(RAC_(TARGET, __VA_ARGS__, nil))舀射,如果是多個(gè)參數(shù)就調(diào)用(RAC_(TARGET, __VA_ARGS__))。



#define RAC_(TARGET, KEYPATH, NILVALUE) \
        [[RACSubscriptingAssignmentTrampoline alloc] initWithTarget:(TARGET) nilValue:(NILVALUE)][@keypath(TARGET, KEYPATH)]


到這里就很明了了怀伦,其實(shí)內(nèi)部就是調(diào)用RACSubscriptingAssignmentTrampoline類的initWithTarget: nilValue:方法脆烟。

我們都知道RAC(TARGET, ...)宏是用來把一個(gè)信號(hào)綁定給一個(gè)對(duì)象的屬性,綁定之后房待,每次信號(hào)發(fā)送出一個(gè)新的值邢羔,就會(huì)自動(dòng)設(shè)定到執(zhí)行的keypath中驼抹。當(dāng)信號(hào)完成之后,這次綁定也會(huì)自動(dòng)的解除拜鹤。

RAC_(TARGET, KEYPATH, NILVALUE) 會(huì)把信號(hào)綁定到TARGET指定的KEYPATH上框冀。如果信號(hào)發(fā)送了nil的值,那么會(huì)替換成NILVALUE賦值給對(duì)應(yīng)的屬性值上敏簿。

RAC_(TARGET, __VA_ARGS__)只不過是RAC_(TARGET, KEYPATH, NILVALUE)第三個(gè)參數(shù)為nil明也。

5. RACChannelTo(TARGET, ...)

RACChannelTo(TARGET, ...)這個(gè)宏完全可以類比RAC(TARGET, ...),兩個(gè)幾乎完全一樣惯裕。



#define RACChannelTo(TARGET, ...) \
    metamacro_if_eq(1, metamacro_argcount(__VA_ARGS__)) \
        (RACChannelTo_(TARGET, __VA_ARGS__, nil)) \
        (RACChannelTo_(TARGET, __VA_ARGS__))


如果只有一個(gè)參數(shù)就調(diào)用(RACChannelTo_(TARGET, __VA_ARGS__, nil)) 温数,如果是多個(gè)參數(shù)就調(diào)用(RACChannelTo_(TARGET, __VA_ARGS__))。(RACChannelTo_(TARGET, __VA_ARGS__))相當(dāng)于是(RACChannelTo_(TARGET, __VA_ARGS__, nil)) 第三個(gè)參數(shù)傳了nil轻猖。



#define RACChannelTo_(TARGET, KEYPATH, NILVALUE) \
    [[RACKVOChannel alloc] initWithTarget:(TARGET) keyPath:@keypath(TARGET, KEYPATH) nilValue:(NILVALUE)][@keypath(RACKVOChannel.new, followingTerminal)]

最終內(nèi)部是調(diào)用了RACKVOChannel的initWithTarget: keyPath: nilValue:方法帆吻。具體原理可以完全類比RAC(TARGET, ...)宏展開,這里不再贅述咙边。

平時(shí)我們都是這樣用:


   RACChannelTo(view, objectProperty) = RACChannelTo(model, objectProperty);
   RACChannelTo(view, integerProperty, @2) = RACChannelTo(model, integerProperty, @10);


6. onExit

宏定義如下:


#define onExit \
    rac_keywordify \
    __strong rac_cleanupBlock_t metamacro_concat(rac_exitBlock_, __LINE__) __attribute__((cleanup(rac_executeCleanupBlock), unused)) = ^



由于rac_keywordify的存在,所以在使用onExit的時(shí)候次员,前面也要加上@符號(hào)败许。

這個(gè)宏比較特殊,最后是跟著一個(gè)閉包淑蔚,比如這樣:


        @onExit {
              free(attributes);
        };

        @onExit {
                [objectLock unlock];
            };


@onExit定義當(dāng)前代碼段退出時(shí)要執(zhí)行的一些代碼市殷。代碼必須用大括號(hào)括起來并以分號(hào)結(jié)尾,無論是何種情況(包括出現(xiàn)異常刹衫,goto語句醋寝,return語句,break語句带迟,continue語句)下跳出代碼段音羞,都會(huì)執(zhí)行onExit后面的代碼。

@onExit提供的代碼被放進(jìn)一個(gè)block塊中仓犬,之后才會(huì)執(zhí)行嗅绰。因?yàn)樵陂]包中,所以它也必須遵循內(nèi)存管理方面的規(guī)則搀继。@onExit是以一種合理的方式提前退出清理塊窘面。

在相同代碼段中如果有多個(gè)@onExit語句,那么他們是按照反字典序的順序執(zhí)行的叽躯。

@onExit語句不能在沒有大括號(hào)的范圍內(nèi)使用财边。在實(shí)際使用過程中,這不是一個(gè)問題点骑,因?yàn)锧onExit后面如果沒有大括號(hào)酣难,那么它是一個(gè)無用的結(jié)構(gòu)谍夭,不會(huì)有任何事情發(fā)生。

最后

關(guān)于ReactiveCocoa里面所有宏的實(shí)現(xiàn)分析都已經(jīng)分析完成鲸鹦。我覺得宏是對(duì)一段邏輯的高度抽象慧库,當(dāng)一個(gè)宏被思維完備的開發(fā)人員設(shè)計(jì)出來以后,就是一個(gè)充滿神奇色彩的魔法馋嗜!如果能把一些簡(jiǎn)單實(shí)用的功能或者邏輯抽象成宏齐板,把這些時(shí)間都節(jié)約到預(yù)編譯中,節(jié)約運(yùn)行時(shí)的時(shí)間葛菇,單從編碼的程度來說甘磨,都是極有樂趣的一件事情!如果以后有機(jī)會(huì)眯停,希望還能和大家交流交流Lisp里面的相關(guān)宏魔法的知識(shí)济舆。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市莺债,隨后出現(xiàn)的幾起案子滋觉,更是在濱河造成了極大的恐慌,老刑警劉巖齐邦,帶你破解...
    沈念sama閱讀 206,378評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件椎侠,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡措拇,警方通過查閱死者的電腦和手機(jī)我纪,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來丐吓,“玉大人浅悉,你說我怎么就攤上這事∪纾” “怎么了术健?”我有些...
    開封第一講書人閱讀 152,702評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)族操。 經(jīng)常有香客問我苛坚,道長(zhǎng),這世上最難降的妖魔是什么色难? 我笑而不...
    開封第一講書人閱讀 55,259評(píng)論 1 279
  • 正文 為了忘掉前任泼舱,我火速辦了婚禮,結(jié)果婚禮上枷莉,老公的妹妹穿的比我還像新娘娇昙。我一直安慰自己,他們只是感情好笤妙,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,263評(píng)論 5 371
  • 文/花漫 我一把揭開白布冒掌。 她就那樣靜靜地躺著噪裕,像睡著了一般。 火紅的嫁衣襯著肌膚如雪股毫。 梳的紋絲不亂的頭發(fā)上膳音,一...
    開封第一講書人閱讀 49,036評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音铃诬,去河邊找鬼祭陷。 笑死,一個(gè)胖子當(dāng)著我的面吹牛趣席,可吹牛的內(nèi)容都是我干的兵志。 我是一名探鬼主播,決...
    沈念sama閱讀 38,349評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼宣肚,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼想罕!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起霉涨,我...
    開封第一講書人閱讀 36,979評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤按价,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后笙瑟,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體俘枫,經(jīng)...
    沈念sama閱讀 43,469評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,938評(píng)論 2 323
  • 正文 我和宋清朗相戀三年逮走,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片今阳。...
    茶點(diǎn)故事閱讀 38,059評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡师溅,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出盾舌,到底是詐尸還是另有隱情墓臭,我是刑警寧澤,帶...
    沈念sama閱讀 33,703評(píng)論 4 323
  • 正文 年R本政府宣布妖谴,位于F島的核電站窿锉,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏膝舅。R本人自食惡果不足惜嗡载,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,257評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望仍稀。 院中可真熱鬧洼滚,春花似錦、人聲如沸技潘。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至铲掐,卻和暖如春拾弃,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背摆霉。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來泰國(guó)打工豪椿, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人斯入。 一個(gè)月前我還...
    沈念sama閱讀 45,501評(píng)論 2 354
  • 正文 我出身青樓砂碉,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親刻两。 傳聞我的和親對(duì)象是個(gè)殘疾皇子增蹭,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,792評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容