Intro
在 Objective-C 中我們可以用 @"foo" 來創(chuàng)建一個 NSString 常量奖恰,看起來似乎平淡無奇够颠。
但它背后其實比想象的精彩橱赠,@ 可以被理解成一個特殊的宏,其接受一個 C 字符串作為參數(shù)超凳,也可寫作 @("foo")钞澳。
之所以說 @ 是一個特殊的宏怠惶,是因為其能根據(jù)傳入的 C 字符串類型不同——C 字符串常量或 C 字符串——在運行時構(gòu)建返回不同類型的 NSString,參見下面的代碼:
```
char* obtain_c_string(void)
{
return"c_string";
}
NSLog(@"%@",?@"foo".class);
NSLog(@"%@",?@("bar").class);
NSLog(@"%@",?@(obtain_c_string()).class);
```
輸出結(jié)果如下:
```
2016-06-05?01:14:15.097?Sandbox[45804:c07]?__NSCFConstantString
2016-06-05?01:14:15.098?Sandbox[45804:c07]?__NSCFConstantString
2016-06-05?01:14:15.098?Sandbox[45804:c07]?__NSCFString
```
可見轧粟,如果傳入的是 C 字符串常量策治,運行時構(gòu)建的則為 NSConstantString;如果傳入的是 C 字符串則創(chuàng)建的是 NSString兰吟。
Then?
你可能會問這么理解了又怎樣通惫?
眾所周知,Objective-C 代碼里有很多地方需要我們把代碼中的一些文法串寫成字符串再作為傳入?yún)?shù)混蔼,比如 KVO 中的 keyPath 參數(shù)往往就要傳入形如 propertyA.propertyB 的字符串讽膏,從實用角度出發(fā)這有兩個弊端:
寫字符串的時候沒有代碼提示,很容易寫錯
即便一開始寫對了拄丰,如果后來相關(guān)類重構(gòu)了府树,keyPath 的參數(shù)便失效了,而 Xcode Refactor 無法掃描字符串
當(dāng)我們理解了 @()料按,再加上自定義的宏奄侠,上述兩個問題便可迎刃而解。
```
/**
*?#?將宏的參數(shù)字符串化载矿,C?函數(shù)?strchr?返回字符串中第一個?'.'?字符的位置
*/
#define?Keypath(keypath)?(strchr(#keypath,?'.')?+?1)
[objA?addObserver:objB
forKeyPath:@Keypath(ObjA.property1.property2)//?有代碼提示垄潮,可以被重構(gòu)掃描到
options:nil
context:nil];
```
這個簡單實現(xiàn)只算是拋磚引玉,除了 @() 配合自定義宏來字符串化代碼中的文法串闷盔,更多的用法就有待在開發(fā)中不斷發(fā)掘了弯洗。
PS: 在即將完成這篇文章的時候我發(fā)現(xiàn)已有國外開發(fā)者利用 @() 特性配合自定義宏,全面系統(tǒng)的解決了上述問題逢勾,詳情參見libextobjc/EXTKeyPathCoding.h牡整。
Extra
此外,@() 還可以接受 int 字面量或 int 變量作為參數(shù)溺拱,比如:
NSString*str=@"hello";
NSLog(@"%@",@(str.length).class);
輸出結(jié)果如下:
2016-08-29 11:26:45.282 testDemo[912:45502] __NSCFNumber
有興趣的讀者可以自行感受下逃贝。