美文网首页
[学习笔记]_四种常用遍历方法(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