2012-01-12 2 views
36

Я как-то наткнулся на ошибку, когда вы пытаетесь удалить объекты из NSMutableArray, в то время как другие объекты добавляются к нему в другом месте. Чтобы это было просто, я не знаю, как это исправить. Вот что я делаю:Объектив-C NSMutableArray, мутированный при перечислении?

У меня есть 4 таймера, которые вызывают 4 разных метода, которые добавляют объект к одному и тому же массиву. Теперь, когда я нажимаю определенную кнопку, мне нужно удалить все объекты в массиве (или, по крайней мере, некоторые). Поэтому я попытался сначала аннулировать все 4 таймера, а затем выполнить работу, которую я хочу с помощью массива, а затем запустить таймеры. Я думал, что это сработало бы, так как я больше не использую таймеры для перечисления через массив, но, похоже, это не работает.

Любые предложения здесь?

+0

Это также происходит со мной, но я ничего не удаляю из своего NSMutableArray. Однако я добавляю в него элементы в фоновом потоке. Он только бросает эту ошибку, может быть, раз каждые 50 или 100, добавляет ... и это единственный поток, который когда-либо затрагивает массив во всем приложении ... – Jesse

ответ

103

Это не имеет никакого отношения к вашим таймерам. Потому что (я полагаю) ваши таймеры работают в том же потоке, что и ваш способ модификации, который вам не нужно останавливать и запускать. IOS не использует прерывания модели для обратных вызовов таймера, они должны ждать своей очереди, как и любое другое событие :)

Вы, вероятно, делать что-то вроде

for (id object in myArray) 
    if (someCondition) 
     [myArray removeObject:object]; 

Вы не можете редактировать изменяемые массив в то время как вы собираетесь через него, так что вам нужно сделать временный массив для хранения вещей, которые вы хотите удалить

// Find the things to remove 
NSMutableArray *toDelete = [NSMutableArray array]; 
for (id object in myArray) 
    if (someCondition) 
     [toDelete addObject:object]; 

// Remove them 
[myArray removeObjectsInArray:toDelete]; 
+0

Я думаю, что последние две строки должны читать «' for (id object in toDelete) [myArray removeObject: object]; '" –

+0

@ TobiasKlüpfel - вы абсолютно правы - я отредактировал свой ответ. – deanWombourne

+0

Просто используйте '-removeObjectsInArray:'. Кроме того, при доступе через индексы вы можете изменять, итерации по нему. –

22

вы можете сделать это следующим образом:

for (id object in [myArray copy]) 
    if (someCondition) 
     [myArray removeObject:object]; 

Как @deanWombourne сказал: «вы не можете редактировать изменчивый массив, пока вы его проходите», так что я делаю здесь, чтобы создать автореализованную копию вашего исходного массива для перечисления объектов, так что вы может безопасно удалить все, что вы хотите.

Более чистый и меньший код котла (я думаю!).

Обновление: Удаленный автоответчик, так как это был старый ответ, предварительно ARC.

+0

Очень приятно :) Может быть проблема с производительностью, если ваш 'myArray' очень большой, и вы только удаляете несколько но мне, конечно, нравится элегантность! – deanWombourne

+0

Большинство изящных здесь, и, конечно, 'autorelease' не требуется с ARC. – mojuba

+0

В дополнение к проблеме производительности @deanWombourne, упомянутой ранее, использование '[myArray copy]' для каждой итерации может замедлить вашу программу. Я бы настоятельно рекомендовал создать экземпляр NSArray (например, 'NSArray * tempArray = [myArray copy];') перед циклом for и использовать его вместо этого. – pxpgraphics

0

Хотя прежде всего являются правдой ... Я хотел бы поделиться своим опытом с

мутировали, будучи перечислены

То, что я делал, было простым, но полностью от ошибок полностью:

for (id obj in d.dataDashBoardGraph) { 
    [tmpData addObject:[obj valueForKey:[[dataToShow[i] componentsSeparatedByString:@"_"] objectAtIndex:1]]]; 

    ... 
} 

Даже это вызвало mutated being enumerated error. Чтобы избавиться от него:

for (id obj in d.dataDashBoardGraph) { 
    NSString *data = [dataToShow[i] copy]; 
    [tmpData addObject:[obj valueForKey:[[data componentsSeparatedByString:@"_"] objectAtIndex:1]]]; 

    ... 
} 

Тогда это сработало отлично.

-1

NSMutableArray не может мутировать, будучи перечислены, вы можете создать небольшую задержку перед вызовом действия:

for(id key in resultsDictionary) { 
       if ([key isEqual:whichButtonString]) { 
        // [resultsDictionary removeObjectForKey:whichButtonString]; 
        [self performSelector:@selector(removeKeyFromDictionary:) withObject:whichButtonString afterDelay:1.0]; 
       } 
      } 

Тогда

-(void) removeKeyFromDictionary : (NSString *) incomingString { 
[resultsDictionary removeObjectForKey:incomingString]; 

}

0

Вы можете попробовать:

for (id object in [myArray reverseObjectEnumerator]) 
if (someCondition) 
    [myArray removeObject:object]; 

Если вы удаляете объект по индексу x => Индекс объектов с индексом x + 1, x + 2 .... будет изменен. Итак, когда вы используете reverseObjectEnumerator, индекс объектов в массиве после удаления некоторых объектов будет по-прежнему исправляться.

Надеюсь, что эта помощь. (принятый ответ - ясное решение.)

Смежные вопросы