Objective-C集合遍历的几种方式

集合遍历的几种方式

简单for循环

    //    定义集合时尽量采用语法糖的格式,简洁高效
    NSDictionary *dictionary = @{ @"1" : @"a",
                                  @"2" : @"b",
                                  @"3" : @"c",
                                  @"4" : @"d"
                                  };
    NSArray *keys = dictionary.allKeys;
    for (int i = 0; i < dictionary.count; i++) {
        NSLog(@"%@ : %@", keys[i], dictionary[keys[i]]);
    }
简单for循环在这里不会赘述,但是我会拿它与for in快速遍历做一个对比,我们普遍认为for in快速遍历一定比for循环快,但是只有在集合中元素很多的情况下这才是对的,当集合中元素很少的情况下for循环比for in循环更快。具体的对比可以参考孙源的这篇博客[iOS 中集合遍历方法的比较和技巧](http://blog.sunnyxx.com/2014/04/30/ios_iterator/)

NSEnumerator枚举遍历

    NSDictionary *dictionary = @{ @"1" : @"a",
                                  @"2" : @"b",
                                  @"3" : @"c",
                                  @"4" : @"d"
                                  };
    NSEnumerator *enumerator = [dictionary objectEnumerator];
    id value = nil;
    while (value = [enumerator nextObject]) {
        NSLog(@"%@",value);
    }
这种形式不得不令人想起Java的迭代器,值得一提的也就是nextObject这个方法了,这个方法返回集合中下一个元素,若没有下一个元素返回nil。这种遍历方式在开发中也很少用到。
使用NSEnumerator对数组进行遍历的时候,还可以倒序遍历:
NSArray *array = @[ @"one",
                        @"two",
                        @"three",
                        @"fourth"
                        ];
NSEnumerator *arrayEnumerator = [array reverseObjectEnumerator];
while (value = [arrayEnumerator nextObject]) {
    NSLog(@"%@",value);
}
值得注意的是:若对可变容器进行遍历时,不可对可变容器修改。如下代码会导致crash。
    NSEnumerator *enumerator = [dictionary objectEnumerator];
    id value = nil;

    while (value = [enumerator nextObject]) {
        NSLog(@"%@",value);
        [dictionary setValue:@"q" forKey:@"a"];

    }

为什么会出现这种原因?
官网上关于NSEnumerator这样说:
The enumerator subclasses used by NSArray, NSDictionary, and NSSet retain the collection during enumeration. When the enumeration is exhausted, the collection is released.
大致的意思是(这次百度翻译挺给力,没有瞎扯淡,毕竟四级没过的人,看官方文档,呵呵):
通过NSArray,NSDictionary使用枚举器类、集合枚举过程中保留和不可变。当枚举耗尽时,集合被释放。
这样就没困惑了。

for in快速遍历

    NSDictionary *dictionary = @{ @"1" : @"a",
                                  @"2" : @"b",
                                  @"3" : @"c",
                                  @"4" : @"d"
                                  };
    for (NSString *key in dictionary) {
        NSLog(@"%@ : %@", key, dictionary[key]);
    }
这种遍历集合的方法在开发中最常用,因为它形式简洁、效率也高。它的缺点是无法访问到集合下标,而且、也是非常值得注意的一点,若对可变容器进行遍历时,不可对可变容器修改。如下代码会导致crash:
NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
[dictionary setObject:@"1" forKey:@"a"];
[dictionary setObject:@"2" forKey:@"b"];
[dictionary setObject:@"3" forKey:@"c"];
[dictionary setObject:@"4" forKey:@"d"];
for (NSString *key in dictionary) {
    NSLog(@"%@ : %@", key, dictionary[key]);
    [dictionary setObject:@"111" forKey:@"a"];
}

Excuse me?这个错误好熟悉?
我们知道for in又称NSFastEnumeration,而NSFastEnumeration又采用了NSEnumerator,所以也有这种缺陷。

基于块的遍历

NSLog(@"------------------------");
    NSArray *array = @[ @"one",
                        @"two",
                        @"three",
                        @"fourth"
                        ];

    [array enumerateObjectsUsingBlock:^(NSString *obj, NSUInteger idx, BOOL *stop) {
        NSLog(@"%@ %lu", obj, (unsigned long)idx);
    }];
    [array enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:^(NSString *obj, NSUInteger idx, BOOL *stop) {
        NSLog(@"%@ %lu", obj, (unsigned long)idx);
    }];
    NSLog(@"------------------------");
    [array enumerateObjectsWithOptions:NSEnumerationConcurrent usingBlock:^(NSString *obj, NSUInteger idx, BOOL *stop) {
        NSLog(@"%@ %lu", obj, (unsigned long)idx);
    }];
    NSLog(@"========================");

运行结果是这样滴:

2016-11-06 13:25:24.274 集合遍历的几种方式[4298:979287] ------------------------
2016-11-06 13:25:24.274 集合遍历的几种方式[4298:979287] one 0
2016-11-06 13:25:24.275 集合遍历的几种方式[4298:979287] two 1
2016-11-06 13:25:24.275 集合遍历的几种方式[4298:979287] three 2
2016-11-06 13:25:24.275 集合遍历的几种方式[4298:979287] fourth 3
2016-11-06 13:25:24.275 集合遍历的几种方式[4298:979287] fourth 3
2016-11-06 13:25:24.276 集合遍历的几种方式[4298:979287] three 2
2016-11-06 13:25:24.276 集合遍历的几种方式[4298:979287] two 1
2016-11-06 13:25:24.276 集合遍历的几种方式[4298:979287] one 0
2016-11-06 13:25:24.276 集合遍历的几种方式[4298:979287] ------------------------
2016-11-06 13:25:24.277 集合遍历的几种方式[4298:979287] one 0
2016-11-06 13:25:24.277 集合遍历的几种方式[4298:979287] three 2
2016-11-06 13:25:24.277 集合遍历的几种方式[4298:979324] two 1
2016-11-06 13:25:24.277 集合遍历的几种方式[4298:979325] fourth 3
2016-11-06 13:25:24.278 集合遍历的几种方式[4298:979287] ========================
对于一个方法,官方这样描述:
Executes a given block using the objects in the array at the specified indexes.By default, the enumeration starts with the first object and continues serially through the array to the last element specified by indexSet. You can specify NSEnumerationConcurrent and/or NSEnumerationReverse as enumeration options to modify this behavior.This method executes synchronously.ImportantIf the block parameter or the indexSet is nil this method will raise an exception.
值得注意的是:
1. 这个方法从集合第一个元素开始,顺序遍历该集合,这和打印结果一样
2. 该方法同步执行这和打印结果一样
对于第二个方法,比第一个方法多了一个参数NSEnumerationReverse,从结果可以看出:遍历顺序为倒序,同步执行。
对与第三个方法,指定了NSEnumerationConcurrent 这个参数,从结果可以看出是无序的,为什么会无序?
因为该块内的遍历是并发执行的。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值