关于可变数组NSMutableArray在三种遍历中(for,for in,enumerate)删除操作的简单了解

大家在实际应用中会遇到这种场景,有一个可变数组,需要删除某些特定的元素,一般情况下自然会想到遍历删除,接下来就给大家讲解一下这几种情况会发生的问题.

第一种:(for in)

    NSMutableArray *array = [NSMutableArray arrayWithObjects:@"1",@"2",@"3",@"4", nil];
    for (NSString *string in array) {
        [array removeObject:array[1]];
    }
    NSLog(@"%@",array);
*** Terminating app due to uncaught exception 'NSGenericException', reason: '*** Collection <__NSArrayM: 0x60400044fc00> was mutated while being enumerated.'

这里的结果直接是crash,原因是什么呢?

因为for in 的原理是根据enumerator对象内部的计数器,调用[nextObject]方法来实现返回下一个数组元素的,直到元素全部返回就会返回nil,于是整个enumerator对象就遍历结束,这种原理来遍历enumerator对象的话,无论对这个对象做什么操作,对象的计数器都不会被重置.
所以当我们使用for in 移除掉一个元素,但是计数器依旧是原来的,那么在遍历到最后会继续调用nextObject方法,而此时实际上已经全部遍历完了,但是系统并不知道,还在遍历,也就是越界;当发现没有元素时,就crash了

第二种:(for)

    NSMutableArray *array = [NSMutableArray arrayWithObjects:@"1",@"2",@"3",@"4", nil];
    for (int i = 0; i < array.count; i++) {
        [array removeObject:array[1]];
    }
    NSLog(@"%@",array);
(
    1,
    4
)

这里的结果并没有crash,但是为什么删除了一个下标元素,而最后只剩下两个元素呢?

这里造成的原因是因为每次读取array.count的时候count就变了,当删除第一个下标为1的元素的时候 array数组里只剩下[@"1",@"3",@"4"]了,然后进行下一次遍历的时候元素3的下标就是1了,所以又把3给删除了,最后只剩下1和4了

第三种:(enumerate)

    NSMutableArray *array = [NSMutableArray arrayWithObjects:@"1",@"2",@"3",@"4", nil];
    [array enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        [array removeObject:array[1]];
    }];
    NSLog(@"%@",array);
(
    1,
    4
)

这里的结果和上面for的结果一样

从这里可以总结得知:for in遍历过程中进行删除操作就会crash,而for和enumerate不会crash,但是会造成数据混乱,多删的现象,所以大家要记住在实际项目中注意这点.

上面这些是根据数组下标删除的,还有一种是直接删除元素,来继续看一下

for in

    NSMutableArray *array = [NSMutableArray arrayWithObjects:@"1",@"2",@"3",@"4", nil];
    for (NSString *string in array) {
        if ([string isEqualToString:@"2"]) {
            [array removeObject:string];
        }
    }
    NSLog(@"%@",array);

    结果:*** Terminating app due to uncaught exception 'NSGenericException', 
    reason: '*** Collection <__NSArrayM: 0x60400044a380> was mutated while being enumerated.'

for

    NSMutableArray *array = [NSMutableArray arrayWithObjects:@"1",@"2",@"3",@"4", nil];
    for (int i = 0; i < array.count; i++) {
        if ([array[i] isEqualToString:@"2"]) {
            [array removeObject:array[i]];
        }
    }
    NSLog(@"%@",array);

    结果:(
      1,
      3,
      4
     )

enumerate

    NSMutableArray *array = [NSMutableArray arrayWithObjects:@"1",@"2",@"3",@"4", nil]; 
    [array enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        if ([obj isEqualToString:@"2"]) {
            [array removeObject:obj];
        }
    }];
    NSLog(@"%@",array);

    结果:(
      1,
      3,
      4
     )
结论: 如果根据判断指定元素去删除的话,for和enumerate不会crash,也不会造成数据混乱,多删的现象,而for in的话照样是crash

最后出一道题供大家思考一下,为什么会crash

    NSMutableArray *array = [NSMutableArray arrayWithObjects:@"1",@"2",@"3",@"4",@"1", nil];
    for (int i = array.count - 1; i >= 0; i--) {
        if ([array[i] isEqualToString:@"1"]) {
            [array removeObject:array[i]];
        }
    }

你可能感兴趣的:(关于可变数组NSMutableArray在三种遍历中(for,for in,enumerate)删除操作的简单了解)