Object-C之块枚举的使用

在编程中经常需要列举collection(包含NSArrray,NSDictionary,NSSet等)中得元素,当前的Object-C语言有很多办法实现此功能,可以用标准的C语言循环,也可以用Object-C 1.0 的NSEnumerator以及Object-C 2.0的快速遍历(fast enumeration)。当语言中引入了“块”这一特性后。又多出几种新的遍历方式,而这几种方式容易被开发者忽视。采用这几种新方式遍历collection时,可以传入块,而collection中得每个元素都可能会放在块里面运行一遍,这种做法通常会大幅度的简化编码过程。如果了解过NSEnumerator的开发者可以直接从“基于块的遍历”看起。如果没有了解过的话,下面的例子会让你快速的了解NSEnumerator和块枚举。小编下面会详细介绍。

for循环

遍历数组的第一种方法就是采用老式的for循环,直接上码,更容易理解。

    //for循环遍历
    //NSArray
    NSArray *anArray = [NSArray arrayWithObjects:@"林志玲",@"范冰冰",@"张馨予", nil];
    for(int i = 0;i < anArray.count;i++)
    {
        id object = anArray[i];
        // do something with "object"
        NSLog(@"object_array:%@",object);
    }

    //Dictionary
    NSDictionary *anDictionary = [NSDictionary dictionaryWithObjectsAndKeys:@"林志玲",@"name",@"15810463139",@"number", nil];
    NSArray *keys = [anDictionary allKeys];
    for(int i = 0;i < keys.count;i++)
    {
        id key = keys[i];
        id value = anDictionary[key];
        // do something with "key" and "value"
        NSLog(@"value:%@ key:%@",value,key);


    }
    //Set
    NSSet *anSet = [NSSet setWithObjects:@"林志玲",@"范冰冰",@"张馨予",nil];
    NSArray *objects = [anSet allObjects];
    for(int i = 0;i < objects.count;i++)
    {
        id object = objects[i];
        // do something with "object"
        NSLog(@"object_set:%@",object);

    }

使用Object-C 1.0 的NSEnumerator 来遍历

NSEnumerator是个抽象基类,其中只定义了两个方法,供其具体子类实现:
allobjects 和 nextObject。其中关键的方法是 nextObject,它返回枚举里面的下个对象。每次调用该方法时,数据结构都会更新。使得下次调用方法时返回下个对象。等到枚举中得所有对象都已经返回之后,再调用就将返回nil,这表示到枚举末端啦。
直接上码吧,更直白。。。。

    //NSEnumerator遍历
    //NSArray
    NSArray *anArray = [NSArray arrayWithObjects:@"林志玲",@"范冰冰",@"张馨予", nil];
    NSEnumerator *enumeratorArr = [anArray objectEnumerator];
    id object;
    while ((object = [enumeratorArr nextObject]) != nil) {
        // do something with "object"
        NSLog(@"object_array:%@",object);
    }

    //Dictionary
    NSDictionary *anDictionary = [NSDictionary dictionaryWithObjectsAndKeys:@"林志玲",@"name",@"15810463139",@"number", nil];
    NSEnumerator *enumeratorDic = [anDictionary objectEnumerator];
    id key;
    while ((key = [enumeratorDic nextObject] )!= nil) {
        id value = anDictionary[key];
        // do something with "key" and "value"
        NSLog(@"value:%@ key:%@",value,key);
    }

    //Set
    NSSet *anSet = [NSSet setWithObjects:@"林志玲",@"范冰冰",@"张馨予",nil];
    NSEnumerator *enumeratorSet = [anSet objectEnumerator];
    id  objectSet;
    while ((objectSet = [enumeratorSet nextObject]) != nil) {
        // do something with "object"
        NSLog(@"object_set:%@",object);

    }

总结:这种写法的功能与标准的for循环相似,但是代码却多了一些。真正的优势在于:不论遍历那种collection,都可以采用这套相似的语法。代码读起来更顺畅。

快速遍历

Object-C 2.0 引入了快速遍历这一功能,快速遍历与使用NSEnumerator 来遍历差不多,然而语法更简洁,它为for循环开设了 in 关键字。这个关键字大幅简化了遍历collection所需的语法。
代码更容易理解

 //快速遍历
    //NSArray
    NSArray *anArray = [NSArray arrayWithObjects:@"林志玲",@"范冰冰",@"张馨予", nil];
    for (id object  in anArray) {
        // do something with "object"
        NSLog(@"object_array:%@",object);
    }

    //Dictionary
    NSDictionary *anDictionary = [NSDictionary dictionaryWithObjectsAndKeys:@"林志玲",@"name",@"15810463139",@"number", nil];
    for (id key in anDictionary) {
        id  value = anDictionary[key];
        // do something with "key" and "value"
        NSLog(@"value:%@ key:%@",value,key);
    }

    //Set
    NSSet *anSet = [NSSet setWithObjects:@"林志玲",@"范冰冰",@"张馨予",nil];
    for (id object in anSet) {
        // do something with "object"
        NSLog(@"object_set:%@",object);

    }

由于NSEnumerator 对象也实现啦NSFastEnumerator协议,所以能用来执行反向遍历。若要用反向遍历数组,可采用下面这种写法:

NSArray *aArray = [NSArray arrayWithObjects:@"林志玲",@"范冰冰",@"张馨予", nil];
    for (id object  in [aArray reverseObjectEnumerator]) {
        // do something with "object"
        NSLog(@"object_array:%@",object);
    }

在目前介绍的遍历方式中,这种方法是语法最简单且效率最高的,然后如果在遍历字典时需要同时获取键与值,那么会多出来一步。缺点是无法获取当前遍历操作所针对的下标。
上面都是开胃菜,了解过NSEnumerator 的开发者可以直接跳到下面的“基于块的遍历方式”。

基于块的遍历方式

在当前的Object-C语言中,最新引入的一种做法就是基于块来遍历。NSArray中定义了下面这个方法,它可以实现最基本的遍历功能:

- (void)enumerateObjectsUsingBlock:(void (^)(id obj, NSUInteger idx, BOOL *stop))block

初次之外,还有一系列类似的遍历方法,它们可以接受各种选项,以便控制遍历操作。在遍历数组及集合时,每次迭代都要执行由block参数所传入的块, 这个块有三个参数,分别是当地前迭代针对的对象,所针对的下标,以及指向布尔值的指针。前两个参数的含义不言而喻。而通过第三个参数所提供的机制,开发者可以终止遍历操作。
先上一段代码消化消化:

NSArray *aArray = [NSArray arrayWithObjects:@"林志玲",@"范冰冰",@"张馨予", nil];
    [aArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
        // do something with "object"
        BOOL shouldStop;
        NSLog(@"obj:%@ idx:%ld",obj,idx);
        if ([obj isEqualToString:@"范冰冰"]) {
            shouldStop = YES;
        }
        if (shouldStop) {
            *stop = YES;
        }
    }];

这种写法稍微多了几行代码,不过依然明晰,而且遍历时既能获取对象,也能知道其下标。此方法还提供了一种很棒的机制,用来终止遍历操作,开发者可以通过stop变量来实现终止操作。当然,使用其他几种遍历方式,也可以通过break来实现终止循环。
此方法不仅可以用来遍历数组。NSSet里面也有同样地块枚举方法,NSDictionary也是这样,只是略有不同。

- (void)enumerateKeysAndObjectsUsingBlock:(void (^)(id key, id obj, BOOL *stop))block

要点

*遍历collection有四种方式。最基本的办法是for循环,其次是NSEnumerator遍历方法及快速遍历,最新,最先进的是“块枚举”法。
*“块枚举”法本身就通GCD来并发执行遍历操作,无须另行编写代码。而采用其他遍历方式无法轻易实现这一点。
*若提前知道待遍历的collection含有何种对象,则应该修改块签名,指出对象的具体类型。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值