Objective-C NSMutableArray мутировал при перечислении?
Я как-то наткнулся на ошибку, где вы пытаетесь удалить объекты из NSMutableArray, в то время как другие объекты добавляются к нему в другом месте. Чтобы это было просто, я не знаю, как это исправить. Вот что я делаю:
У меня есть 4 таймера, которые вызывают 4 разных метода, которые добавляют объект к одному и тому же массиву. Теперь, когда я нажимаю определенную кнопку, мне нужно удалить все объекты в массиве (или, по крайней мере, некоторые). Поэтому я попытался сначала аннулировать все 4 таймера, а затем выполнить работу, которую я хочу с помощью массива, а затем запустить таймеры. Я думал, что это сработало бы, так как я больше не использую таймеры для перечисления через массив, но, похоже, это не работает.
Любые предложения здесь?
Ответы
Ответ 1
Это не имеет никакого отношения к вашим таймерам. Потому что (я полагаю) ваши таймеры работают в том же потоке, что и ваш способ модификации, который вам не нужно останавливать и запускать. 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];
Ответ 2
Вы можете сделать это следующим образом:
for (id object in [myArray copy])
if (someCondition)
[myArray removeObject:object];
Как и @deanWombourne, "вы не можете редактировать изменчивый массив, пока вы его проходите", поэтому я делаю здесь, чтобы создать автореализованную копию исходного массива для перечисления объектов, поэтому вы может безопасно удалить все, что вы хотите.
Более чистый и менее кодовый код (я думаю!).
Обновить. Удалено автозапуск, так как это был старый ответ, pre ARC.
Ответ 3
Вы можете использовать директиву @synchronized() для блокировки массива, когда вы его мутируете:
if (someCondition) {
@synchronized(yourArray) {
[yourArray removeObject:someObject];
}
}
Дополнительная информация на http://developer.apple.com/library/ios/#documentation/cocoa/conceptual/objectivec/Chapters/ocThreading.html
Ответ 4
Хотя все верно... Я бы поделился своим опытом с
мутировался при перечислении
То, что я делал, было простым, но полным ошибкой:
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]]];
...
}
Тогда он работал отлично.
Ответ 5
Вы можете попробовать:
for (id object in [myArray reverseObjectEnumerator])
if (someCondition)
[myArray removeObject:object];
Если вы удаляете объект по индексу x = > Индекс объектов с индексом x + 1, x + 2.... будет изменен.
Поэтому, когда вы используете reverseObjectEnumerator, индекс объектов в массиве после удаления некоторых объектов будет по-прежнему исправляться.
Надеюсь на эту помощь.
(принятый ответ - четкое решение.)
Ответ 6
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];
}