文章轉(zhuǎn)自http://nshipster.cn/
另外iOS 中集合遍歷方法的比較和技巧 · sunnyxx的技術(shù)博客這篇文章對于KVC 集合運算符的性能也做了描述
Ruby愛好者總愛嘲笑Objective-C臃腫的語法奈搜。
盡管新的Object Literals特性讓我們的語法瘦了幾斤锈遥,但那些紅頭發(fā)的惡霸們還總是用他們的單行map
和花哨的Symbol#to_proc
來嘲諷我們。
實際上祟印,一門語言是否優(yōu)雅歸結(jié)起來就是其怎么樣能更好的避免循環(huán)篮奄。for
库糠,while
語句是一種拖累槐臀;即使是快速枚舉也一樣蜡峰。無論你怎么樣使他們看起來更加的友好葡幸,循環(huán)依然是一個在自然語言中用非常簡單方式描述所做事情的代碼塊
"給我這個列表里面所有員工的平均薪酬"最筒,等等。蔚叨。床蜘。
Objective-C
double totalSalary = 0.0;
for (Employee *employee in employees) {
totalSalary += [employee.salary doubleValue];
}
double averageSalary = totalSalary / [employees count];
╮(╯_╰)╭
幸運的是辙培,鍵-值編碼給我們了一種更加簡潔的,幾乎像Ruby一樣的方式來做這件事:
Objective-C
[employees valueForKeyPath:@"@avg.salary"];
KVC集合運算符允許在valueForKeyPath:
方法中使用key path符號在一個集合中執(zhí)行方法邢锯。無論什么時候你在key path中看見了@
扬蕊,它都代表了一個特定的集合方法,其結(jié)果可以被返回或者鏈接丹擎,就像其他的key path一樣尾抑。
集合運算符會根據(jù)其返回值的不同分為以下三種類型:
- 簡單的集合運算符 返回的是strings, number, 或者 dates
- 對象運算符 返回的是一個數(shù)組
- 數(shù)組和集合運算符 返回的是一個數(shù)組或者集合
要理解其工作原理,最好方式就是去action里面看看蒂培。想象一個Product
類和一個由以下數(shù)據(jù)所組成的products
數(shù)組:
Objective-C
@interface Product : NSObject
@property NSString *name;
@property double price;
@property NSDate *launchedOn;
@end
鍵-值 編碼會在必要的時候把基本數(shù)據(jù)類型的數(shù)據(jù)自動裝箱和拆箱到
NSNumber
或者NSValue
中來確保一切工作正常蛮穿。
Name | Price | Launch Date |
---|---|---|
iPhone 5 | $199 | September 21, 2012 |
iPad Mini | $329 | November 2, 2012 |
MacBook Pro | $1699 | June 11, 2012 |
iMac | $1299 | November 2, 2012 |
簡單集合操作符
-
@count
: 返回一個值為集合中對象總數(shù)的NSNumber
對象。 -
@sum
: 首先把集合中的每個對象都轉(zhuǎn)換為double
類型毁渗,然后計算其總践磅,最后返回一個值為這個總和的NSNumber
對象。 -
@avg
: 把集合中的每個對象都轉(zhuǎn)換為double
類型灸异,返回一個值為平均值的NSNumber
對象府适。 -
@max
: 使用compare:
方法來確定最大值。所以為了讓其正常工作肺樟,集合中所有的對象都必須支持和另一個對象的比較檐春。 -
@min
: 和@max
一樣,但是返回的是集合中的最小值么伯。
例如:
Objective-C
[products valueForKeyPath:@"@count"]; // 4
[products valueForKeyPath:@"@sum.price"]; // 3526.00
[products valueForKeyPath:@"@avg.price"]; // 881.50
[products valueForKeyPath:@"@max.price"]; // 1699.00
[products valueForKeyPath:@"@min.launchedOn"]; // June 11, 2012
Pro提示:你可以簡單的通過把self作為操作符后面的key path來獲取一個由
NSNumber
組成的數(shù)組或者集合的總值疟暖,例如[@[@(1), @(2), @(3)] valueForKeyPath:@"@max.self"]
(感謝 @davandermobile, 來自 Objective Sea)
對象操作符
想象下,我們有一個inventory
數(shù)組田柔,代表了當(dāng)?shù)靥O果商店的當(dāng)前庫存(iPad Mini不足俐巴,并且沒有新的iMac,因為還沒有發(fā)貨):
Objective-C
NSArray *inventory = @[iPhone5, iPhone5, iPhone5, iPadMini, macBookPro, macBookPro];
-
@unionOfObjects
/@distinctUnionOfObjects
: 返回一個由操作符右邊的key path所指定的對象屬性組成的數(shù)組硬爆。其中@distinctUnionOfObjects
會對數(shù)組去重, 而且@unionOfObjects
不會.
例如:
Objective-C
[inventory valueForKeyPath:@"@unionOfObjects.name"]; // "iPhone 5", "iPhone 5", "iPhone 5", "iPad Mini", "MacBook Pro", "MacBook Pro"
[inventory valueForKeyPath:@"@distinctUnionOfObjects.name"]; // "iPhone 5", "iPad Mini", "MacBook Pro"
數(shù)組和集合操作符
數(shù)組和集合操作符跟對象操作符很相似欣舵,只不過它是在NSArray
和NSSet
所組成的集合中工作的。如果我們做一些例如:比較幾個商店中的庫存(和我們上一節(jié)類似的appleStore庫存
和買iPhone 5和iPad Mini的versizonStore庫存
)這樣的工作缀磕,這個就會很有用缘圈。
@distinctUnionOfArrays
/@unionOfArrays
: 返回了一個數(shù)組,其中包含這個集合中每個數(shù)組對于這個操作符右面指定的key path進行操作之后的值袜蚕。正如你期望的糟把,distinct
版本會移除重復(fù)的值。@distinctUnionOfSets
: 和@distinctUnionOfArrays
差不多, 但是它期望的是一個包含著NSSet
對象的NSSet
牲剃,并且會返回一個NSSet
對象遣疯。因為集合不能包含重復(fù)的值,所以它只有distinct
操作颠黎。
例如:
Objective-C
[@[appleStoreInventory, verizonStoreInventory] valueForKeyPath:@"@distinctUnionOfArrays.name"]; // "iPhone 5", "iPad Mini", "MacBook Pro"
這可能是一個可怕的想法
令人好奇的是另锋,蘋果的KVC集合操作符文檔冒出了下面這個提示:
注意: 目前還不能自定義集合操作符。
這個提示是有意義的狭归,因為大多數(shù)人在第一次看到集合運算符時都在想這個夭坪。
然而,事實證明过椎,在我們的小伙伴objc/runtime
的幫助下室梅,這個實際上 是 有可以能的實現(xiàn)的。
Guy English有一篇很神奇的文章疚宇,在文章中亡鼠,他swizzles valueForKeyPath:
來解析自定義的DSL敷待,其擴展了一些有趣的效果:
Objective-C
NSArray *names = [allEmployees valueForKeyPath: @"[collect].{daysOff<10}.name"];
這段代碼可以得到只有休了不足10天假期的人的名字(無疑是要提醒他們?nèi)バ輦€假吧<浜)
或者,來看個可笑的極端情況:
Objective-C
NSArray *albumCovers = [records valueForKeyPath:@"[collect].{artist like 'Bon Iver'}.<NSUnarchiveFromDataTransformerName>.albumCoverImageData"];
Ruby小伙伴們羨慕吧榜揖。只用一行就在藝人記錄中過濾出來了名字叫"Bon Iver"的藝人勾哩,并且用匹配到的專輯的專輯封面的圖像數(shù)據(jù)初始化了一個NSImage
對象。
這是一個好的想法嗎举哟?可能不是思劳。(NSPredicate
更加合適,并且其使得邏輯更加簡單妨猩,易懂)
這個很酷嗎潜叛?當(dāng)然啦!這個聰明的例子展示了Objective-C DSL和元編程未來可能的發(fā)展方向壶硅。
KVC集合運算符是一個想節(jié)省幾行代碼并在這一過程中看起來很酷的人必須要了解的威兜。當(dāng)像Ruby這樣的腳本語言自夸它的單行能力是多么的靈活時,我們也許應(yīng)該花一點兒時間來慶祝Objective-C中的約束和集合操作符庐椒。畢竟牡属,Ruby非常非常慢,我說的對嗎扼睬?
作者Mattt Thompson (@mattt) is the creator & maintainer of AFNetworking and other popular open-source projects, including Postgres.app, ASCIIwwdc and Nomad.
翻譯者Candyan 專業(yè) iOS逮栅,業(yè)余 Android,偶爾搗鼓下Server的工程師窗宇。