【问题标题】:Need to modify an NSMutableArray that is pre-loaded with data during fast enumeration in iOSiOS快速枚举时需要修改一个预加载数据的NSMutableArray
【发布时间】:2012-12-18 20:04:18
【问题描述】:

我有一个保存对象列表的 NSMutableArray。我想要做的是遍历这个对象列表,并为我要插入的对象找到匹配的对象。一旦找到匹配的对象,我就想简单地用我要插入的对象替换当前列表中的对象。我正在尝试使用快速枚举来做到这一点:

TestResult *result = [[TestResult alloc] init];
    [result setName:name];
    [result setScore:score];
    [result setDateStamp:date];


    for (TestResult *checkTest in [DataModel sharedInstance].testResultList) {

        NSInteger indx = [[DataModel sharedInstance].testResultList indexOfObjectPassingTest:^BOOL(TestResult *obj, NSUInteger idx, BOOL *stop) {
            return [obj.name isEqualToString:name];
        }];

        if (indx != NSNotFound) {

            [[DataModel sharedInstance].testResultList replaceObjectAtIndex:indx withObject:result];

        }

    }

不幸的是,当我运行上述代码时,我收到以下错误:

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

谁能看到我做错了什么,如何解决这个问题,同时实现我上面描述的功能?

【问题讨论】:

    标签: ios nsmutablearray enumeration fast-enumeration


    【解决方案1】:

    首先,崩溃是不言自明的。 你实际上是在变异(也就是替换数组中的一个对象),而快速枚举仍在进行中,这是不允许的。

    如果您愿意采用您的设计,解决方案是实际捕获对象的索引,中断快速枚举并替换快速枚举之外的对象。

    但是您所做的不正确。 indexOfObjectPassingTest 的使用方法是这样的:

    NSInteger indx = [[DataModel sharedInstance].testResultList indexOfObjectPassingTest:^BOOL(TestResult *obj, NSUInteger idx, BOOL *stop) {
        return [obj.name isEqualToString:name];
    }];
    
    if (indx != NSNotFound) {
    
        [[DataModel sharedInstance].testResultList replaceObjectAtIndex:indx withObject:result];
    
    }
    

    您不需要手动枚举数组的所有元素。 该函数在内部为您执行此操作。

    【讨论】:

    • 非常感谢您告诉我如何做到这一点。我觉得比以前更无知了:-)
    • @Lefteris,+1。你说的对。该枚举是不必要的。
    • @syedfa 我们仍在为更有经验的开发人员学习。问也不错,从错误中吸取教训也不错!
    • @ACB 它引起了我的注意,因为我想知道为什么 syedfa 会这样做,这就是我立即发现它的原因。
    • 再次感谢 Lefteris。保重。
    【解决方案2】:

    正如错误消息所说,您不能修改在 foreach bucle 中使用的数组。将您的代码更改为:

    TestResult *result = [[TestResult alloc] init];
    [result setName:name];
    [result setScore:score];
    [result setDateStamp:date];
    
    NSInteger indx = NSNotFound;
    for (TestResult *checkTest in [DataModel sharedInstance].testResultList) {
    
        indx = [[DataModel sharedInstance].testResultList indexOfObjectPassingTest:^BOOL(TestResult *obj, NSUInteger idx, BOOL *stop) {
            return [obj.name isEqualToString:name];
        }];
    }
    if (indx != NSNotFound) {
        [[DataModel sharedInstance].testResultList replaceObjectAtIndex:indx withObject:result];                            
    }
    

    【讨论】:

      【解决方案3】:

      枚举时不能替换、删除或插入数组中的元素。但是您可以将idxn 的元素的所有属性更改为result 的属性。这样对象就保留了。

      希望这会有所帮助!

      【讨论】:

        【解决方案4】:

        正如错误消息所说,您无法编辑正在枚举的数组。你需要有一个不同的数组,然后你才能做到这一点。

        以下方法会起作用,

        TestResult *result = [[TestResult alloc] init];
        [result setName:name];
        [result setScore:score];
        [result setDateStamp:date];
        
        NSArray *array = [NSArray arrayWithArray:[DataModel sharedInstance].testResultList];    
        
        for (TestResult *checkTest in array) {
        
            NSInteger indx = [[DataModel sharedInstance].testResultList indexOfObjectPassingTest:^BOOL(TestResult *obj, NSUInteger idx, BOOL *stop) {
                return [obj.name isEqualToString:name];
            }];
        
            if (indx != NSNotFound) {
                [[DataModel sharedInstance].testResultList replaceObjectAtIndex:indx withObject:result];
            }
        }
        

        更新: 根据 Lefteris 的评论,如果您使用 indexOfObjectPassingTest 方法,则不需要遍历数组。

        你可以简单地使用,

        TestResult *result = [[TestResult alloc] init];
        [result setName:name];
        [result setScore:score];
        [result setDateStamp:date];
        
        NSInteger indx = [[DataModel sharedInstance].testResultList indexOfObjectPassingTest:^BOOL(TestResult *obj, NSUInteger idx, BOOL *stop) {
            return [obj.name isEqualToString:name];
        }];
        
        if (indx != NSNotFound) {
            [[DataModel sharedInstance].testResultList replaceObjectAtIndex:indx withObject:result];
        }
        

        【讨论】:

        • 我很惊讶您没有发现明显的错误,并在 indexOfObjectsPassing 测试 NSArray 方法之上进行快速枚举。
        • @Lefteris,是的,你是对的。我实际上并没有按照逻辑思考。我更关注 OP 提到的问题。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-12-10
        相关资源
        最近更新 更多