转载请注明出处!!!

如以下代码:

NSMutableArray *array = [NSMutableArray arrayWithObjects:@"2",@"3",@"4",@"9",@"4",@"12",@"22",@"4",@"4",@"5",@"6",@"1", nil];

     for (NSString *str in array) {

        if ([str isEqualToString:@"4"]) {

            [array removeObject:str];

        }

     }

运行后肯定会crash,原因是数组越界。这是为什么?当我们正序快速遍历时,如果删除了一个,那么没有遍历到的元素位置都会往前移动一位,这样系统就无法确定接下来遍历是从删除位置开始呢,还是从删除位置下一位开始呢?这样就造成程序crash了。但是我们想要遍历删除时要怎么做?解决这个问题的方法有好几种。

出现这个崩溃的事件只会出现在快速遍历中。如果像以下代码不采用快速遍历,而是使用for循环,就不会出现问题。

for (int i = 0; i < array.count; i++) {

        NSString *str  = array[i];

        if ([str isEqualToString:@"4"]) {

            [array removeObject:str];

        }

     }

这两种有什么区别呢?

https://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/Classes/NSEnumerator_Class/index.html

这是Apple官方文档中关于快速遍历的利弊。其中的note中显示,建议最好不要再快速遍历的时候修改enumerator,否则不保证是安全的.由此就明白了,可能是我们在快速遍历的时候,移除掉一个元素,但是计数器依旧是原来的,那么在遍历到最后会继续调用nextObject方法,而此时实际上已经全部遍历完了,但是系统并不知道,还在遍历,也就是越界;当发现没有元素时,就crash了;而我写的常规遍历法为什么就可以呢,那是因为i < self.btnArray.count,这个判断条件中,当数组元素个数变化时,self.btnArray.count也在变,就不会出现数组越界的情况,因此第二种方法是可行的;

第二种解决方法是定义一个副数组,遍历副本中的元素,在原数组中删除。

NSMutableArray *copyArray = [NSMutableArray arrayWithArray:array];

     for (NSString *str in copyArray) {

        if ([str isEqualToString:@"4"]) {

            [array removeObject:str];

        }

     }

第三种方法是对数组逆序遍历,查找对应元素后删除

NSEnumerator *enumerator = [array reverseObjectEnumerator];

     for (NSString *str in enumerator) {

        if ([str isEqualToString:@"4"]) {

            [array removeObject:str];

        }

     }

对于逆序遍历,因为我们逆序遍历时,遇到匹配的元素删除后,位置改变的是遍历过得元素,而没有遍历到的元素位置却没有改变,所以遍历能够正常进行.就不会crash。

   解决方法列了这么几种,本人能力有限,如果有更好建议或者有什么不足,请联系我。

for循环删除数组中的元素crash问题的更多相关文章

  1. JS实现循环删除数组中元素的方法介绍

    这篇文章主要给大家介绍了关于Javascript循环删除数组中元素的几种方法,文中给出了详细的示例代码供大家参考学习,对大家具有一定的参考学习价值,需要的朋友们下面来一起看看吧. 本文主要跟大家分享了 ...

  2. js 删除 数组中某个元素(转载)

    来源:https://www.jb51.net/article/134312.htm js删除数组中某一项或几项的几种方法 https://www.jb51.net/article/154737.ht ...

  3. Javascript循环删除数组中元素的几种方法示例

    发现问题 大家在码代码的过程中,经常会遇到在循环中移除指定元素的需求.按照常规的思路,直接一个for循环,然后在循环里面来个if判断,在判断中删除掉指定元素即可.但是实际情况往往不会像预想的那样顺利运 ...

  4. js删除数组中的元素delete和splice的区别

    例如有一个数组是 :var textArr = ['a','b','c','d']; 这时我想删除这个数组中的b元素: 方法一:delete 删除数组 delete textArr[1]  结果为:  ...

  5. Python笔记:用for循环删除列表中的元素

    for运行过程中会有一个指针来记录当前循环的元素是哪一个,一开始这个指针指向第0个元素,然后获取它,接着删除第0个元素,这时候,原来是第1个的元素会变成第0个,当指针向后移动一次,指向了现在第1个元素 ...

  6. Java如何删除数组中的元素?

    Java中,如何删除数组元素? 示例 以下示例显示如何从数组中删除元素. package com.yiibai; import java.util.ArrayList; public class Re ...

  7. python循环删除list中的元素

    直接上例子: a = [1,2,3,4,5,6] for i in a: a.remove(i) print(a) 返回:[2, 4, 6] 循环a,想删除a的所有元素,但实际确有数据保留了下来,这是 ...

  8. jquery删除数组中重复元素

    首先定义如下数组: var arr=[0,2,3,5,6,9,2]; 我们可以看到数组中存在重复元素'2'; 最后通过jquery筛选应该得到[0,2,3,5,6,9]; ok,首先我们再定义一个空数 ...

  9. [Perl] 删除数组中重复元素

    写一个小程序时候,需要去除一个数组中的重复元素,搜索了一下,找到的代码主要是两种,一种是使用grep函数,一种是转换为hash表,代码分别如下: 使用grep函数代码片段:代码: my @array ...

  10. JS中删除数组中的元素方法

    删除指定下标数组元素 Array.prototype.del=function(index){ if(isNaN(index)||index>=this.length){ return fals ...

随机推荐

  1. 如何在FastAPI中玩转WebSocket消息处理?

    扫描二维码 关注或者微信搜一搜:编程智域 前端至全栈交流与成长 发现1000+提升效率与开发的AI工具和实用程序:https://tools.cmdragon.cn/ 一.文本消息接收与发送 # 运行 ...

  2. C#中数组(byte[])复制 拷贝

    https://blog.csdn.net/alisa525/article/details/12518927 1,Array.Copy在CLR处理机制中最灵活,最强大,可装箱,拆箱复制,可加宽CLR ...

  3. Oracle并发控制

    并发与锁定 当多用户同一时刻访问相同的数据库资源时,将产生并发.并发极易破坏数据的一致性.锁定是处理并发的重要手段,用户在修改某一资源前,必须首先获得资源的修改权.而这种修改权具有排他性. 并发与锁定 ...

  4. Flink初体验-批处理与流处理

    一.环境准备 本机环境:jdk11.scala2.12.maven3.6 新建一个maven项目,pom如下 <?xml version="1.0" encoding=&qu ...

  5. JF 笔试 反思

    ifconfig  是  window ipconfig  是  linux下的 搞混了 还有子网的信息,不清楚 有空看吧 所谓的Virtual Judge是区别于Online Judge而言的,OJ ...

  6. c++ stl iterator erase

    简介 就是C++ 标准库程序删除元素. 其实很简单,只是做个记录 it = monkeys.erase(it); //删除元素后,迭代器失效, //要重新让迭代器指向被删元素的后面

  7. iPaaS丨企业应用及数据集成的重要性和挑战

    在激烈的市场竞争中,企业服务总线和数据总线扮演着企业神经网络的角色,它们将不同的业务部门.系统以及数据紧密相连,保障信息流通无阻,实现资源的高效分配.这样的集成不仅提高了企业的运营效率,还增强了企业的 ...

  8. Streamlit入门 中文文档

    基础概念 使用 Streamlit 进行开发非常简单.首先,在普通的 Python 脚本中添加几条 Streamlit 命令,然后使用 streamlit run 命令来运行它: streamlit ...

  9. Linux 系统启动过程-九五小庞

    linux启动时我们会看到许多启动信息. Linux系统的启动过程并不是大家想象中的那么复杂,其过程可以分为5个阶段: 内核的引导. 运行 init. 系统初始化. 建立终端 . 用户登录系统. in ...

  10. 进阶篇:2.3)DFMA的运用方法(个人方法)

    本章目的:将DFMA运用到实际中,个人方法谈. 1.DFMA事后补缺的运用步骤(实践) 1)准备DFMA设计检查表格(如果你所在公司用的是DFMA专用软件,请忽略): 2)准备设计原则对应的资料书籍: ...