久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

Reactive Cocoa Tutorial [1] = 神奇的Macros · sunnyxx的技術(shù)博客

 ccccshq 2016-06-14

Reactive Cocoa Tutorial 系列,,轉(zhuǎn)載請(qǐng)注明該文源地址 – by sunnyxx


先說說RAC中必須要知道的宏:

RAC(TARGET, [KEYPATH, [NIL_VALUE]])

使用:

RAC(self.outputLabel, text) = self.inputTextField.rac_textSignal;
RAC(self.outputLabel, text, @"收到nil時(shí)就顯示我") = self.inputTextField.rac_textSignal;

  這個(gè)宏是最常用的,,RAC()總是出現(xiàn)在等號(hào)左邊,等號(hào)右邊是一個(gè)RACSignal,,表示的意義是將一個(gè)對(duì)象的一個(gè)屬性和一個(gè)signal綁定,,signal每產(chǎn)生一個(gè)value(id類型),,都會(huì)自動(dòng)執(zhí)行:

[TARGET setValue:value ?: NIL_VALUE forKeyPath:KEYPATH];

  數(shù)字值會(huì)升級(jí)為NSNumber *,,當(dāng)setValue:forKeyPath時(shí)會(huì)自動(dòng)降級(jí)成基本類型(int, float ,BOOL等),所以RAC綁定一個(gè)基本類型的值是沒有問題的

  · RACObserve(TARGET, KEYPATH)

  作用是觀察TARGET的KEYPATH屬性,,相當(dāng)于KVO,,產(chǎn)生一個(gè)RACSignal

  最常用的使用,和RAC宏綁定屬性:

RAC(self.outputLabel, text) = RACObserve(self.model, name);

  上面的代碼將label的輸出和model的name屬性綁定,,實(shí)現(xiàn)聯(lián)動(dòng),,name但凡有變化都會(huì)使得label輸出

@weakify(Obj);
@strongify(Obj);

  這對(duì)宏在 RACEXTScope.h 中定義,RACFramework好像沒有默認(rèn)引入,,需要單獨(dú)import

  他們的作用主要是在block內(nèi)部管理對(duì)self的引用

@weakify(self); // 定義了一個(gè)__weak的self_weak_變量
[RACObserve(self, name) subscribeNext:^(NSString *name) {
@strongify(self); // 局域定義了一個(gè)__strong的self指針指向self_weak
self.outputLabel.text = name;
}];

  這個(gè)宏為什么這么吊,,前面加@,其實(shí)就是一個(gè)啥都沒干的@autoreleasepool {}前面的那個(gè)@,,為了顯眼罷了,。

  這兩個(gè)宏一定成對(duì)出現(xiàn),先weak再strong

除了RAC中常用宏的使用,有一些宏的實(shí)現(xiàn)方法也很值得觀摩,。

  舉個(gè)高級(jí)點(diǎn)的栗子:

  要干的一件事,,計(jì)算一個(gè)可變參數(shù)列表的長度

  第一反應(yīng)就是用參數(shù)列表的api,,va_start va_arg va_end遍歷一遍計(jì)算個(gè)和,,但仔細(xì)想想,對(duì)于可變參數(shù)這個(gè)事,,在編譯前其實(shí)就已經(jīng)確定了,,代碼里括號(hào)里有多少個(gè)參數(shù)一目了然。

  RAC中Racmetamarcos.h中就有一系列宏來完成這件事,,硬是在預(yù)處理之后就拿到了可變參數(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)

這個(gè)宏由幾個(gè)工具宏一層層展開,,現(xiàn)在模擬一下展開過程:

假如我們要計(jì)算的如下:

int count = metamacro_argcount(a, b, c);

于是乎第一層展開后:

int count = metamacro_at(20, a, b, c, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1)

再看metamacro_at的定義:

#define metamacro_at(N, ...) metamacro_concat(metamacro_at, N)(__VA_ARGS__)
// 下面是metamacro_concat做的事(簡寫一層)
#define metamacro_concat_(A, B) A ## B

于是乎第二層展開后:

int count = metamacro_at20(a, b, c, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1);

再看metamacro_at20這個(gè)宏干的事兒:

#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__)

于是乎第三層展開后,,相當(dāng)于截?cái)嗔饲?0個(gè)參數(shù),留下剩下幾個(gè):

int count = metamacro_head(3, 2, 1);

這個(gè)metamacro_head:

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

  后面加個(gè)0,,然后取參數(shù)列表第一個(gè),,于是乎:

int count = 3;

  大功告成。

  反正我看完之后感覺挺震驚,,宏還能這么用,,這樣帶來的好處不止是將計(jì)算在預(yù)處理時(shí)搞定,不拖延到運(yùn)行時(shí)惡心cpu,;但更重要的是編譯檢查,。比如某些可變參數(shù)的實(shí)現(xiàn)要求可以填2個(gè)參數(shù),可以填3個(gè)參數(shù),,其他的都不行,,這樣,,也只有這樣的宏的實(shí)現(xiàn),,才能在編譯前就確定了錯(cuò)誤。

除了上面,,還有一個(gè)神奇的宏的使用:

  當(dāng)使用諸如RAC(self, outputLabel)RACObserve(self, name)時(shí),發(fā)現(xiàn)寫完逗號(hào)之后,,輸入第二個(gè)property的時(shí)候會(huì)出現(xiàn)完全正確的代碼提示,!這相當(dāng)神奇。
自動(dòng)代碼提示

探究一下,,關(guān)鍵的關(guān)鍵是如下一個(gè)宏:

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

這個(gè)metamacro_argcount上面說過,,是計(jì)算可變參數(shù)個(gè)數(shù),所以metamacro_if_eq的作用就是判斷參數(shù)個(gè)數(shù),,如果個(gè)數(shù)是1就執(zhí)行后面的keypath1,,若不是1就執(zhí)行keypath2。

所以重點(diǎn)說一下keypath2:

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

  乍一看真挺懵,,先化簡,,由于Objc里面keypath是諸如”outputLabel.text”的字符串,所以這個(gè)宏的返回值應(yīng)該是個(gè)字符串,,可以簡化成:

#define keypath2(OBJ, PATH) (???????, # PATH)

先不管”??????”是啥,,這里不得不說C語言中一個(gè)不大常見的語法(第一個(gè)忽略):

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

這些都是逗號(hào)表達(dá)式的合理用法,第三個(gè)最不常用了,,c將被b賦值,,而a是一個(gè)未使用的值,編譯器會(huì)給出warning,。

去除warning的方法很簡單,,強(qiáng)轉(zhuǎn)成void就行了:

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

再看上面簡化的keypath2宏,返回的就是PATH的字符串字面值了(單#號(hào)會(huì)將傳入值轉(zhuǎn)成字面字符串)

(((void)(NO && ((void)OBJ.PATH, NO)), # PATH))

對(duì)傳入的第一個(gè)參數(shù)OBJ和第二個(gè)正要輸入的PATH做了點(diǎn)操作,這也正是為什么輸入第二個(gè)參數(shù)時(shí)編輯器會(huì)給出正確的代碼提示,。強(qiáng)轉(zhuǎn)void就像上面說的去除了warning,。

 但至于為什么加入與NO&&,我不太能理解,,我測試時(shí)其實(shí)沒有時(shí)已經(jīng)完成了功能,,可能是作者為了屏蔽某些隱藏的問題吧。

  這個(gè)宏的巧妙的地方就在于使得編譯器以為我們要輸入“點(diǎn)”出來的屬性,,保證了輸入值的合法性(輸了不存在的property直接報(bào)錯(cuò)的),,同時(shí)利用了逗號(hào)表達(dá)式取逗號(hào)最后值的語法返回了正確的keypath。

總之

RAC對(duì)宏的使用達(dá)到了很高的水平,,還有諸如RACTuplePack,,RACTupleUnpack的宏就不細(xì)說了,值得研究,。


PS:上面介紹的metamacro和@strongify等宏確切來說來自RAC依賴的extobjc,,作者是Justin Spahr-Summers,正是RAC作者之一,。

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn),。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式,、誘導(dǎo)購買等信息,謹(jǐn)防詐騙,。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多