美文网首页
[学习笔记]_四种常用遍历方法(NSArray,NSDictio

[学习笔记]_四种常用遍历方法(NSArray,NSDictio

作者: figure_ai | 来源:发表于2016-09-08 21:00 被阅读0次

第一种方式:for循环

  • 遍历数组

    NSArray *iosArray = @[@"L", @"O", @"V", @"E", @"I", @"O", @"S"];
    
    for (int i = 0; i < iosArray.count; i++) {
        
        //处理数组中数据
        
        NSLog(@"%@", iosArray[i]);
        
    }
    
    
  • 遍历字典

    NSDictionary *dict = @{@"1":@"11", @"2":@"22", @"3":@"33"};
    
    NSArray *keysArray = [dict allKeys];
    
    for (int i = 0; i < keysArray.count; i++) {
    
    //根据键值处理字典中的每一项
    
    NSString *key = keysArray[i];
    
    NSString *value = dict[key];
    
    NSLog(@"%@", value);
    
    }
    
    
    • 因为字典和set是无序的,所以我们无法根据特定的整数下标来直接访问其中的值,于是需要先获取字典中的键或者set的所有对象,这样就可以在有序数组上进行遍历了。然而创建出多一个数组,会保留collection中的所有对象,占用了内存
  • 优缺点:

    • 优点:被广泛使用,容易接受,操作简单

    • 缺点:遍历字典和set比较繁琐,会占用比较多的系统资源


第二种方式:快速遍历


  • 遍历数组

    NSArray *iosArray = @[@"L", @"O", @"V", @"E", @"I", @"O", @"S"];
    for (NSString*obj in iosArray) {
        
        //处理数组中的数据
        if ([obj isEqualToString:@"E"]) {
            NSLog(@"%@",obj);
        }
    }
    
    

    执行结果

    2016-09-02 11:35:38.553 bianli_demo[1914:78780] E
    
  • 遍历字典

NSDictionary *dict = @{@"1":@"11", @"2":@"22", @"3":@"33"};

for (NSString *key in dict) {
    if ([key isEqualToString:@"2"]) {
        NSLog(@"%@",dict[key]);
    }
}
```

执行结果

```
2016-09-02 11:35:38.553 bianli_demo[1914:78780] 22
```
- 反向遍历可以使用for(NSString *obj in [iosArray reverseObjectEnumerator])
  • 总结:
    • 优点:语法简洁,使用方便,效率高;
    • 缺点:
      • 1.无法方便获取当前遍历的下标
      • 2.无法再遍历过程中修改被遍历的collection,否则会导致崩溃

第三种方式:NSEnumerator


  • NSEnumerator是一个抽象基类,其中定义了2个方法,使其子类实现:

    (nullable ObjectType)nextObject;

    @property(readonly,copy)NSArray*allObjects;

    其中nextObject是关键方法,它返回枚举里的下一个对象,每次调用改方法,内部结构都会更新,使得下一次调用方法时能返回下一个对象,等到枚举中全部的对象都已经返回之后,再调用就会返回nil,表示达到了枚举的末端。

  • 遍历数组

    NSEnumerator *enumerator = [_iosArray objectEnumerator];//正向遍历
    
    id object ;
    
    while ((object = [enumerator nextObject])!= nil) {
        //处理枚举器中的数据
        NSLog(@"object = %@",object);
    }
    
    

    执行结果

    2016-09-02 12:03:25.043 get&post-test[2146:91583] object = L
    2016-09-02 12:03:25.044 get&post-test[2146:91583] object = O
    2016-09-02 12:03:25.044 get&post-test[2146:91583] object = V
    2016-09-02 12:03:25.044 get&post-test[2146:91583] object = E
    2016-09-02 12:03:25.044 get&post-test[2146:91583] object = I
    2016-09-02 12:03:25.044 get&post-test[2146:91583] object = O
    2016-09-02 12:03:25.044 get&post-test[2146:91583] object = S
    
    
  • 遍历字典

    NSEnumerator *enumerator2 = _dict.keyEnumerator;
    id obj2 ;
    while ((obj2= [enumerator2 nextObject]) != nil) {
        NSLog(@"obj2_keyValue = %@",_dict[obj2]);
    }
    

    执行结果

    2016-09-02 12:03:25.044 get&post-test[2146:91583] obj2_keyValue = 11
    

2016-09-02 12:03:25.045 get&post-test[2146:91583] obj2_keyValue = 22
2016-09-02 12:03:25.045 get&post-test[2146:91583] obj2_keyValue = 33
```

  • 总结
    • 优点:代码容易读,不需要定义额外的数组
- 缺点:
    
    1.无法直接获取遍历操作的下表,需要另外声明变量记录

    2.需要自行创建NSEnumerator对象。

第四种:基于块的遍历方式


  • 苹果封装的高效、优雅、易用的一套接口,笔者极力推荐的使用方法

  • 遍历数组

    self.iosArray = @[@"L", @"O", @"V", @"E", @"I", @"O", @"S"];
    /**
     *  遍历数组
     *
     *  @param obj  表示数组中元素
     *  @param idx  表示元素的下标
     *  @param stop 控制遍历何时停止,使用要在前面加*
     *
     *  @return
     */ 
    [_iosArray enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        
        NSLog(@"%@",obj);
        
        if ([obj isEqualToString:@"O"]) {
            
            *stop = YES;
        
        }
        
    }];
    
    

    执行结果

    2016-09-02 14:47:28.441 get&post-test[2282:121901] L
    2016-09-02 14:47:28.441 get&post-test[2282:121901] O
    
  • 遍历字典

    NSDictionary *dict = @{@"1":@"11", @"2":@"22", @"3":@"33"};
    
    /**
     *  遍历字典
     *
     *  @param key  字典key值
     *  @param obj  字典value值
     *  @param stop 控制遍历何时停止
     *
     *  @return
     */
    [_dict enumerateKeysAndObjectsUsingBlock:^(id  _Nonnull key, id  _Nonnull obj, BOOL * _Nonnull stop) {
    
    NSLog(@"key = %@",key);
    NSLog(@"value = %@",obj);
    
    if ([key isEqualToString:@"2"]) {
        *stop = YES;
    }
    
    }];
    

    执行结果

    2016-09-02 14:54:38.816 get&post-test[2349:125565] value = 11
    2016-09-02 14:54:38.816 get&post-test[2349:125565] key = 2
    2016-09-02 14:54:38.816 get&post-test[2349:125565] value = 22
    
    

  • 注意
    • 若已知collection里对象的数据类型,可以修改块签名。知道对象的精确类型后,编译器就可以检测开发者是否调用了该对象所不具有的方法,并在发现问题是报错。

      NSDictionary *dict = @{@"1":@"11", @"2":@"22", @"3":@"33"};
      
      //此处直接将key和value的类型改为nsstring
      [dict enumerateKeysAndObjectsUsingBlock:^(NSString key, NSString obj, BOOL * _Nonnull stop) {
      
      NSLog(@"%@", obj);
      
      if ([obj isEqualToString:@"22"]) {
      
      *stop = YES;
      
      }
      
      }];
      
      

  • 反向遍历

    //反向遍历数组
    [_iosArray enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
       
        NSLog(@"%@",obj);
        if (obj == nil) {
            *stop = YES;
        }
        
    }];
    
    //反向遍历字典
    [_dict enumerateKeysAndObjectsWithOptions:NSEnumerationReverse usingBlock:^(NSString* key, NSString* obj, BOOL * _Nonnull stop) {
        
        NSLog(@"key = %@, value = %@",key,obj);
        
        if (key == nil) {
            *stop = YES;
        }
        
    }];
    

    执行结果

    2016-09-02 15:14:49.776 get&post-test[2527:135482] S
    2016-09-02 15:14:49.777 get&post-test[2527:135482] O
    2016-09-02 15:14:49.777 get&post-test[2527:135482] I
    2016-09-02 15:14:49.777 get&post-test[2527:135482] E
    2016-09-02 15:14:49.777 get&post-test[2527:135482] V
    2016-09-02 15:14:49.777 get&post-test[2527:135482] O
    2016-09-02 15:14:49.777 get&post-test[2527:135482] L
    2016-09-02 15:14:49.778 get&post-test[2527:135482] key = 1, value = 11
    2016-09-02 15:14:49.778 get&post-test[2527:135482] key = 2, value = 22
    2016-09-02 15:14:49.778 get&post-test[2527:135482] key = 3, value = 33
    

  • 并发遍历

    • 并发遍历:NSEnumerationConcurrent;也就是可以同时遍历collection的几个元素,具体数量根据系统资源而定,这样会充分利用系统资源,高效快捷的完成collection的遍历,系统底层会通过gcd来处理并发事宜,开发者不需担心内存和线程,其他方式若要实现高效的并发遍历十分有难度,通过块枚举遍历,改变collection不会引期代码崩溃

      NSArray *iosArray = @[@"L", @"O", @"V", @"E", @"I", @"O", @"S"];
      
      NSMutableArray *iosMutableArray = [NSMutableArray arrayWithArray:iosArray];
      
      [iosMutableArray enumerateObjectsWithOptions:NSEnumerationConcurrent usingBlock:^(NSString *obj, NSUInteger idx, BOOL * _Nonnull stop) {
      
      obj = [NSString stringWithFormat:@"_%@", obj];
      
      [iosMutableArray replaceObjectAtIndex:idx withObject:obj];
      
      NSLog(@"%@", obj);
      
      if ([obj isEqualToString:@"_I"]) {
      
      *stop = YES;
      
      }
      
      }];
      
      

      执行结果

      2016-09-02 15:27:06.123 get&post-test[2599:140840] _V
      2016-09-02 15:27:06.123 get&post-test[2599:140708] _L
      2016-09-02 15:27:06.124 get&post-test[2599:140708] _I
      2016-09-02 15:27:06.123 get&post-test[2599:140837] _E
      2016-09-02 15:27:06.124 get&post-test[2599:140708] _S
      2016-09-02 15:27:06.123 get&post-test[2599:140838] _O
      2016-09-02 15:27:06.124 get&post-test[2599:140840] _O
      
      
  • 总结

    • 优点
      • 1.可以完美实现for循环的所有功能。
      • 2.可以方便获取集合中的每一项元素。
      • 3.可以修改块签名
      • 4.可以实现并发循环功能,系统底层会通过gcd处理并发事宜
      • 5.效率高,能够提升程序性能,开发者可以专注于业务逻辑,而不必担心线程和内存问题
      • 6.提供了循环遍历的参数,NSEnumerationReverse用来实现倒序循环。NSEnumerationConcurrent用来实现并发遍历,两个参数可以同时使用;
    • 缺点
      • 1.这里使用了block,需要注意在block里容易引起的保留环问题,比如使用self调用方法时,把self转化成弱引用即可打破保留环。如__weak __typeof(self)weakSelf = self 或者 __weak MyController *weakSelf = self; 在block里使用weakSelf即可。

  • 注意

    使用基于块的遍历时是可以修改遍历的元素的,不会导致崩溃,但是如果
    要删除遍历的元素会导致后面的元素无法遍历而崩溃,解决办法有2种
    1、一种是复制一份原集合的副本,对副本进行操作,找出所要操作的元素后再处理原集合
    2、使用反向遍历,反向遍历删除元素后不会导致崩溃。
    

相关文章

网友评论

      本文标题:[学习笔记]_四种常用遍历方法(NSArray,NSDictio

      本文链接:https://www.haomeiwen.com/subject/ckxeettx.html