引言
無論那種語(yǔ)言,我們都會(huì)大量的去操作collection(集合),對(duì)collection不停的做增刪該查,OC也不例外。而當(dāng)我們對(duì)collection做操作的時(shí)候應(yīng)該時(shí)刻關(guān)注操作復(fù)雜度,包括時(shí)間復(fù)雜度和空間復(fù)雜度,使自己的代碼用盡可能低的內(nèi)存消耗和盡可能少的時(shí)間來完成需求。本文旨在以“黑盒”的方式來比較OC中用不同的方法遍歷NSMutableArray和NSMutableDictionary中的值所用的時(shí)間。
環(huán)境
- MACBook Pro 2.7 GHz Intel Core i5
- MAC OS X 10.11.6 (15G1004)
- XCode Version 8.2 (8C38)
步驟
1,創(chuàng)建ZMTest工程,在ViewController中定義如下屬性
@property (nonatomic, strong) NSMutableArray *testArray;
@property (nonatomic, strong) NSMutableDictionary *testDictionary;
2,初始化
self.testArray = [NSMutableArray new];
self.testDictionary = [NSMutableDictionary new];
for (int i = 0; i <= 10000000; i ++) {
NSString *value = [NSString stringWithFormat:@"%d",i];
[self.testArray addObject:value];
[self.testDictionary setValue:value forKey:value];
}
3,引入獲取代碼運(yùn)行時(shí)間的宏(這是公司一個(gè)大神寫的,地址 )
/** 快速查詢一段代碼的執(zhí)行時(shí)間 */
/** 用法
TICK
do your work here
TOCK
*/
#define TICK NSDate *startTime = [NSDate date];
#define TOCK NSLog(@"Time:%f\n", -[startTime timeIntervalSinceNow]);
4,實(shí)現(xiàn)如下方法
- (void)testArraty1{
TICK
for (int i = 0; i < self.testArray.count; i ++) {
if ([self.testArray[i] isEqualToString:@"10000000"]) {
NSLog(@"testArraty1");
}
}
TOCK
}
- (void)testArraty2{
TICK
NSInteger *index = 0;
for (NSString *value in self.testArray) {
index = index + 1;
if ([value isEqualToString:@"10000000"]) {
NSLog(@"testArraty2");
}
}
TOCK
}
- (void)testArraty3{
TICK
[self.testArray enumerateObjectsUsingBlock:^(NSString * value, NSUInteger i, BOOL * _Nonnull stop) {
if ([value isEqualToString:@"10000000"]) {
NSLog(@"testArraty3");
}
}];
TOCK
}
- (void)testDictionary1{
TICK
[self.testDictionary enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSString *obj, BOOL * _Nonnull stop) {
if ([key isEqualToString:@"10000000"]) {
NSLog(@"testDictionary1");
}
}];
TOCK
}
- (void)testDictionary2{
TICK
NSArray *allKey = [self.testDictionary allKeys];
for (NSString * key in allKey) {
NSString *value = self.testDictionary[key];
if ([key isEqualToString:@"10000000"]) {
NSLog(@"testDictionary2");
}
}
TOCK
}
然后再viewDidLoad方法中調(diào)用這幾個(gè)方法
5,運(yùn)行,結(jié)果如下

以下是整理的表格
| 方法 | 耗時(shí) | 說明 |
|---|---|---|
| testArraty1 | 1.530919 | Execute code for each value in a sequence of values(不會(huì)翻譯??,就是最簡(jiǎn)單的for循環(huán)) |
| testArraty2 | 0.131923 | NSFastEnumeration協(xié)議方法 |
| testArraty3 | 0.489827 | 基于塊的遍歷 |
| testDictionary1 | 0.674507 | 基于塊的遍歷 |
| testDictionary2 | 2.830808 | 通過allKey是方法獲取所有的key,然后通過key獲取value |
6,結(jié)論
(1)在遍歷NSArray的時(shí)候最好使用NSFastEnumeration協(xié)議的這種方式(for...in...),效率明顯高于通過定義索引然后檢索的方式,當(dāng)然為了操作簡(jiǎn)單,也可以使用基于塊的方式來遍歷,基于block的方式遍歷的好處也顯而易見,直接可以獲取到下標(biāo)、值和跳出循環(huán)的BOOL值,當(dāng)然該方式的的耗時(shí)也高于NSFastEnumeration協(xié)議的方式,不過,我覺得可以接受。
(2)在遍歷NSDictionary的時(shí)候,請(qǐng)務(wù)必使用基于block的形式,不僅大量的降低時(shí)耗,而且能獲取到key、value和跳出循環(huán)的BOOL值??芍^方便快捷。
最后
接觸的新東西的越多。越覺得自己欠缺,最近在看《編寫高質(zhì)量IOS與OS X代碼的52個(gè)有效方法》一書,真心推薦。而本文也算是書中一個(gè)章節(jié)的讀后感。