iOS开发实用技巧—Objective-C中的各种遍历(迭代)方式


  说明:

  1)该文简短介绍在iOS开发中遍历字典、数组和集合的几种常见方式。

  2)该文对应的代码可以在下面的地址获得:https://github.com/HanGangAndHanMeimei/Code

 

一、使用for循环

  要遍历字典、数组或者是集合,for循环是最简单也用的比较多的方法,示例如下: 

复制代码
 1 //普通的for循环遍历
 2 -(void)iteratorWithFor
 3 {
 4     //处理数组//
 5     NSArray *arrayM = @[@"1",@"2",@"3",@"4"];
 6     NSInteger arrayMCount = [arrayM count];
 7     for (int i = 0; i<arrayMCount; i++) {
 8         NSString *obj = arrayM[i];
 9         NSLog(@"%@",obj);
10     }
11 
12     //处理字典//
13     NSDictionary *dictM = @{@"1":@"one",@"2":@"two",@"3":@"three"};
14     NSArray *dictKeysArray = [dictM allKeys];
15     for (int i = 0; i<dictKeysArray.count; i++) {
16         NSString *key = dictKeysArray[i];
17         NSString *obj = [dictM objectForKey:key];
18         NSLog(@"%@:%@",key,obj);
19     }
20 
21     //处理集合//
22     NSSet * setM = [[NSSet alloc] initWithObjects:@"one",@"two",@"three",@"four", nil];
23     NSArray *setObjArray = [setM allObjects];
24     for (int i = 0; i<setObjArray.count; i++) {
25         NSString *obj = setObjArray[i];
26         NSLog(@"%@",obj);
27     }
28 
29     //反向遍历----降序遍历----以数组为例
30     NSArray *arrayM2 = @[@"1",@"2",@"3",@"4"];
31     NSInteger arrayMCount2 = [arrayM2 count] - 1;
32 
33     for (NSInteger i = arrayMCount2; i>0; i--) {
34         NSString *obj = arrayM2[i];
35         NSLog(@"%@",obj);
36     }
37 }
复制代码

优点:简单

缺点:由于字典和集合内部是无序的,导致我们在遍历字典和集合的时候需要借助一个新的『数组』作为中介来处理,多出了一部分开销。

 

二、使用NSEnumerator遍历

NSEnumerator的使用和基本的for循环类似,不过代码量要大一些。示例如下:

复制代码
 1 //使用NSEnumerator遍历
 2 -(void)iteratorWithEnumerator
 3 {
 4     //处理数组//
 5     NSArray *arrayM = @[@"1",@"2",@"3",@"4"];
 6     NSEnumerator *arrayEnumerator = [arrayM objectEnumerator];
 7     NSString *obj;
 8     while ((obj = [arrayEnumerator nextObject]) != nil) {
 9         NSLog(@"%@",obj);
10     }
11 
12     //处理字典//
13     NSDictionary *dictM = @{@"1":@"one",@"2":@"two",@"3":@"three"};
14     NSEnumerator *dictEnumerator = [dictM keyEnumerator];
15     NSString *key;
16     while ((key = [dictEnumerator nextObject]) != nil) {
17         NSString *obj = dictM[key];
18         NSLog(@"%@",obj);
19     }
20 
21 
22     //处理集合//
23     NSSet * setM = [[NSSet alloc] initWithObjects:@"one",@"two",@"three",@"four", nil];
24     NSEnumerator *setEnumerator = [setM objectEnumerator];
25     NSString *setObj;
26     while ((setObj = [setEnumerator nextObject]) != nil) {
27         NSLog(@"%@",setObj);
28     }
29 
30 
31     //反向遍历----降序遍历----以数组为例
32     NSArray *arrayM2 = @[@"1",@"2",@"3",@"4"];
33     NSEnumerator *arrayEnumerator2 = [arrayM2 reverseObjectEnumerator];
34     NSString *obj2;
35     while ((obj2 = [arrayEnumerator2 nextObject]) != nil) {
36         NSLog(@"%@",obj2);
37     }
38 
39 }
复制代码

优点:对于不同的数据类型,遍历的语法相似;内部可以简单的通过reverseObjectEnumerator设置进行反向遍历。

缺点:代码量稍大。

 

三、使用for...In遍历

在Objective-C 2.0 中增加了for ...In 形式的快速遍历。此种遍历方式语法简洁,速度飞快。示例如下:

复制代码
 1 //使用for...In进行快速遍历
 2 -(void)iteratorWithForIn
 3 {
 4     //处理数组//
 5     NSArray *arrayM = @[@"1",@"2",@"3",@"4"];
 6     for (id obj in arrayM) {
 7         NSLog(@"%@",obj);
 8     }
 9 
10     //处理字典//
11     NSDictionary *dictM = @{@"1":@"one",@"2":@"two",@"3":@"three"};
12     for (id obj in dictM) {
13         NSLog(@"%@",dictM[obj]);
14     }
15 
16     //处理集合//
17     NSSet * setM = [[NSSet alloc] initWithObjects:@"one",@"two",@"three",@"four", nil];
18     for (id obj in setM) {
19         NSLog(@"%@",obj);
20     }
21 
22     //反向遍历----降序遍历----以数组为例
23     NSArray *arrayM2 = @[@"1",@"2",@"3",@"4"];
24     for (id obj in [arrayM2 reverseObjectEnumerator]) {
25         NSLog(@"%@",obj);
26     }
27 }
复制代码

优点:1)语法简洁;2)效率最高;

缺点:无法获得当前遍历操作所针对的下标。

 

四、基于Block的遍历方式

基于Block的方式来进行遍历是最新引入的方法。它提供了遍历数组|字典等类型数据的最佳实践。示例如下:

复制代码
 1 //基于块(block)的遍历方式
 2 -(void)iteratorWithBlock
 3 {
 4     //处理数组//
 5     NSArray *arrayM = @[@"1",@"2",@"3",@"4"];
 6     [arrayM enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
 7         NSLog(@"%zd--%@",idx,obj);
 8     }];
 9 
10     //处理字典//
11     NSDictionary *dictM = @{@"1":@"one",@"2":@"two",@"3":@"three"};
12     [dictM enumerateKeysAndObjectsUsingBlock:^(id  _Nonnull key, id  _Nonnull obj, BOOL * _Nonnull stop) {
13         NSLog(@"%@:%@",key,obj);
14     }];
15 
16     //处理集合//
17     NSSet * setM = [[NSSet alloc] initWithObjects:@"one",@"two",@"three",@"four", nil];
18     [setM enumerateObjectsUsingBlock:^(id  _Nonnull obj, BOOL * _Nonnull stop) {
19         NSLog(@"%@",obj);
20     }];
21 
22     //反向遍历----降序遍历----以数组为例
23     NSArray *arrayM2 = @[@"1",@"2",@"3",@"4"];
24     [arrayM2 enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
25         NSLog(@"%zd--%@",idx,obj);
26     }];
27 }
复制代码

优点:1)遍历时可以直接从block中获得需要的所有信息,包括下标、值等。特别相对于字典而言,不需要做多余的编码即可同时获得key和value的值。

   2)能够直接修改block中key或者obj的类型为真实类型,可以省去类型转换的工作。

   3)可以通过NSEnumerationConcurrent枚举值开启并发迭代功能。

说明:基于Block的遍历方式在实现反向遍历的时候也非常简单,使用enumerateObjectsWithOptions方法,传递NSEnumerationReverse作为参数即可,在处理遍历操作的时候推荐基于Block的遍历方式。

 

五、使GCD中的dispatch_apply函数

  使用GCD中的dispatch_apply函数也能实现字典、数组等的遍历,该函数比较适合处理耗时较长、迭代次数较多的情况。示例如下:

复制代码
 1 //使用GCD中的dispatch_apply函数
 2 -(void)iteratorWithApply
 3 {
 4     //处理数组//
 5     NSArray *arrayM = @[@"1",@"2",@"3",@"4"];
 6 
 7     //获得全局并发队列
 8     dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
 9 
10     dispatch_apply(arrayM.count, queue, ^(size_t index) {
11         NSLog(@"%@--%@",arrayM[index],[NSThread currentThread]);
12     });
13 }
复制代码

优点:开启多条线程并发处理遍历任务,执行效率高。

缺点:1)对于字典和集合的处理需借助数组;2)无法实现反向遍历。


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/248027.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

windows系统作为客户端时,linux中本地yum源挂载时,如何同时挂载DVD1和DVD2?

这里以CentOS6.5为例.他的镜像有两个DVD1和DVD2.DVD1中是系统和主要的安装包,DVD2中是剩下的安装包 当挂载时如果要同时挂载DVD1和DVD2.需要这样做: 1)在虚拟机的设置中选择连接 2)分别在mnt下创建cdrom和cdrom1文件夹 3)到dev下查看有软连接 cdrom->sr0 cdrom1->sr1 这里…

Ajax — 大事件项目(第二天)

大事件-02 fix一个bug 原因&#xff1a; 开始做注册的时候&#xff0c;页面中只有一个 namepassword的input&#xff0c;所以 $(‘input[name“password”]’) 可以准确的找到元素后来做登录的时候&#xff0c;页面中多了一个namepassword的input&#xff0c;所以$(‘input[…

OpenCV自带dnn的Example研究(3)— object_detection

这个博客系列&#xff0c;简单来说&#xff0c;今天我们就是要研究https://docs.opencv.org/master/examples.html下的6个文件&#xff0c;看看在最新的OpenCV中&#xff0c;它们是如何发挥作用的。在配置使用的过程中&#xff0c;需要注意使用较高版本的VS避免编译器兼容问题&…

Ajax — 大事件项目(第三天)

大事件-03 用户信息 表单验证 html中&#xff0c;直接使用layui提供的内置验证规则 email <input type"text" name"email" required lay-verify"required|email" placeholder"请输入邮箱" autocomplete"off" class&q…

iOS中监测来电方案

问题 最近在做一个有录音功能的App&#xff0c;要求当用户接到来电时&#xff0c;要停止录音。该如何实现这个功能呢&#xff1f; 解决方案 我首先想到了AppDelegate里的applicationWillResignActive:方法&#xff0c;在该方法的注释中就写到到收到来电或短信时&#xff0c;系统…

iOS运行时-使用Runtime向Category中添加属性以及运行时介绍

前言 了解OC的都应该知道&#xff0c;在一般情况下&#xff0c;我们是不能向Category中添加属性的&#xff0c;只能添加方法&#xff0c;但有些情况向&#xff0c;我们确实需要向Category中添加属性&#xff0c;而且很多系统的API也有一些在Category添加属性的情况&#xff0c;…

Ajax — cropper (图片剪裁)基本用法

jQuery-cropper插件完整的API&#xff1a;http://www.jq22.com/jquery-info9322 1. 基本使用步骤 在 <head> 中导入 cropper.css 样式表&#xff1a; <link rel"stylesheet" href"/assets/lib/cropper/cropper.css" />在 <body> 的结…

「短篇小说」灵囚 540 天

转载&#xff1a;知乎 - BIMBOX 孙彬 - https://zhuanlan.zhihu.com/p/24655832 「我们总有一天会逾越那条上帝划好的界限&#xff0c;而最终我们将无法面对真实和虚假&#xff0c;正义与罪恶。」 「不幸的是&#xff0c;从伊甸园那一次&#xff0c;我们就已经越界了。」 第十天…

iOS 够逼格的注释总结

首先关于注意这里就不说什么VVDocument了&#xff0c;来点新鲜的&#xff01; 也许你使用过#warning 警告提示 也许你也使用过#pragma marks。 但是你见过或者使用过下面这个吗&#xff1f; Comments containing:MARK:TODO:FIXME:!!!:???: 没有&#xff0c;那么你就快速的看…

Git图形化管理工具

Git图形化管理工具 注意&#xff1a;必须在创建的仓库中进行右键打开 复制这段内容后打开百度网盘App&#xff0c;操作更方便哦。 链接&#xff1a;https://pan.baidu.com/s/1eXIk01LXSmzmXvYfw3MnEA 提取码&#xff1a;J166 --来自百度网盘超级会员V5的分享 分类 sourceTr…

TCP/IP(一):数据链路层

背景 这一系列的文章主要是为一般的、非专业开发岗位(如移动端)的工程师准备&#xff0c;一方面可以对网络的基本知识有基本的了解&#xff0c;另一方面不至于面试中被问到相关问题时束手无策。知识以 TCP/IP 协议簇为主&#xff0c;也会有应用层和数据链路层的简单介绍。 文…

富文本和封面制作

1. 富文本编辑器的实现步骤 添加如下的 layui 表单行&#xff1a; <div class"layui-form-item"><!-- 左侧的 label --><label class"layui-form-label">文章内容</label><!-- 为富文本编辑器外部的容器设置高度 --><div…

Linux系统编程——线程(1)

目录 线程概要Linux内核线程实现原理线程的共享/不共享资源线程优缺点线程控制原语pthread_selfpthread_createpthread_exitpthread_joinpthread_cancel终止线程方式控制原语对比前情提要&#xff1a; Linux用户级线程和内核级线程区别 线程概要 Linux内核线程实现原理 类Unix系…

TCP/IP(二):IP协议

IP协议处于OSI参考模型的第三层——网络层&#xff0c;网络层的主要作用是实现终端节点间的通信。IP协议是网络层的一个重要协议&#xff0c;网络层中还有ARP(获取MAC地址)和ICMP协议(数据发送异常通知) 数据链路层的作用在于实现同一种数据链路下的包传递&#xff0c;而网络层…

Ajax — 大事件项目(第四天)

分类管理 添加分类 初步使用弹出层 给 “添加分类” 绑定一个单击事件单击事件中&#xff0c;使用 layer.open() 实现一个弹出层 type: 1, 弹层的类型是页面层title, “添加文字分类”content: ‘字符串&#xff0c;DOM’,area: [‘500px’, ‘250px’] // ---------------…

redis学习(四)

一、Redis 键(key) 1、Redis 键命令用于管理 redis 的键。 2、Redis 键命令的基本语法如下&#xff1a;redis 127.0.0.1:6379> COMMAND KEY_NAME 3、常用key命令 keys * 获取所有的keyselect 0 选择第一个库move myString 1 将当前的数据库key移动到某个…

TCP/IP(三):IP协议相关技术

在前两篇文章中&#xff0c;我分别介绍了数据链路层和网络层的IP协议。虽然这个系列教程的重点是搞定 TCP/IP&#xff0c;不过不用着急&#xff0c;本文简要介绍完与 IP 协议相关的技术&#xff0c;下一篇文章就会正式、详细的介绍 传输层与 TCP 协议。这篇文章会介绍 DNS、ARP…

Node — 第一天

Node-01 会 JavaScript&#xff0c;就能学会 Node.js&#xff01;&#xff01;&#xff01; **Node.js 的官网地址&#xff1a; ** Node.js 的学习路径&#xff1a; JavaScript 基础语法 Node.js 内置 API 模块&#xff08;fs、path、http等&#xff09; 第三方 API 模块&…

TCP/IP(四):TCP 与 UDP 协议简介

从本章开始&#xff0c;我们开始介绍最重要的传输层。传输层位于 OSI 七层模型的第四层&#xff08;由下往上&#xff09;。顾名思义&#xff0c;传输层的主要作用是实现应用程序之间的通信。网络层主要是保证不同数据链路下数据的可达性&#xff0c;至于如何传输数据则是由传输…

Node — 第二天

http模块 搭建服务器的步骤 ① 导入 http 模块 ② 创建 web 服务器实例 ③ 为服务器实例绑定 request 事件&#xff0c;监听客户端的请求 ④ 启动服务器 // ① 导入 http 模块 const http require(http);// ② 创建 web 服务器实例 const server http.createServer();/…