Получение исключения NSGenericException с причиной: "*** Коллекция <NSConcreteHashTable: 0x282c34140> была изменена при перечислении".

Я получаю это исключение NSGenericException по причине Collection <NSConcreteHashTable: 0x282c34140> was mutated while being enumerated хотя я на самом деле не использую быстрое перечисление в своем коде.

Этот сбой запускается, когда делегат NSFetchedResultsController вызывается при обновлении свойства в моем объекте Core Data, что в конечном итоге вызывает этот метод:

- (void)mutateCoordinatesOfClashingAnnotations:(NSArray *)annotations {

    NSDictionary *coordinateValuesToAnnotations = [self groupAnnotationsByLocationValue:annotations]; // returns a dictionary with key: coordinate (saved as NSValue) -> NSMutableArray of MKAnnotation objects

    for (int i=0; i<coordinateValuesToAnnotations.allKeys.count; i++) {
        NSValue *coordinateValue = coordinateValuesToAnnotations.allKeys[i];
        NSMutableArray *outletsAtLocation = coordinateValuesToAnnotations[coordinateValue];

        [self repositionAnnotations:outletsAtLocation];
    }
}

- (void)repositionAnnotations:(NSMutableArray *)annotations {

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

        double heading = radiansBetweenAnnotations * i;
        CLLocationCoordinate2D newCoordinate = [self calculateNewCoordinate];

        id <MKAnnotation> annotation = annotations[i];
        annotation.coordinate = newCoordinate; // this is where it crashes
    }
}

По сути, я пытаюсь изменить значение "координаты" для объекта MKAnnotation (который на самом деле тоже является CoreData NSManagedObject), что приводит к сбою. Как ни странно, я получаю ошибку "коллекция была изменена при перечислении", хотя в приведенном выше коде не происходит "быстрого перечисления". Я имею в виду, что я изменяю одно свойство объекта внутри изменяемого массива, который сам является частью словаря.

К сожалению, поскольку "аннотация" является NSManagedObject, я не могу просто "скопировать" ее из массива, а затем изменить скопированное значение и заменить объект внутри массива.

Отчет о сбое выглядит так:

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

Last Exception Backtrace:
0   CoreFoundation                       0x00000001c058696c __exceptionPreprocess + 224
1   libobjc.A.dylib                      0x00000001c029f028 objc_exception_throw + 56
2   CoreFoundation                       0x00000001c05862d4 __NSFastEnumerationMutationHandler + 120
3   libobjc.A.dylib                      0x00000001c02b21a4 objc_enumerationMutation + 28
4   Foundation                           0x00000001c08706a8 -[NSConcreteHashTable countByEnumeratingWithState:objects:count:] + 72
5   MapKit                               0x00000001ce114b64 -[MKAnnotationManager observeValueForKeyPath:ofObject:change:context:] + 804
6   Foundation                           0x00000001c093bf14 NSKeyValueNotifyObserver + 288
7   Foundation                           0x00000001c093e01c NSKeyValueDidChange + 332
8   Foundation                           0x00000001c093b740 NSKeyValueDidChangeWithPerThreadPendingNotifications + 148
9   CoreData                             0x00000001c5006e38 _PF_ManagedObject_DidChangeValueForKey + 76
10  Foundation                           0x00000001c093784c NSKVOForwardInvocation + 336
11  CoreFoundation                       0x00000001c058adc0 ___forwarding___ + 676
12  CoreFoundation                       0x00000001c058d3a0 _CF_forwarding_prep_0 + 92
13  CJournal                             0x00000001049fc930 -[MapViewShared repositionAnnotations:] (MapViewShared.m:656)
14  CJournal                             0x00000001049fc580 -[MapViewShared mutateCoordinatesOfClashingAnnotations:] (MapViewShared.m:616)
15  CJournal                             0x0000000104a1fa98 -[MapViewController controllerDidChangeContent:] (MapViewController.m:1104)
16  CoreData                             0x00000001c50572a4 __82-[NSFetchedResultsController(PrivateMethods) _core_managedObjectContextDidChange:]_block_invoke + 5868
17  CoreData                             0x00000001c5015aac developerSubmittedBlockToNSManagedObjectContextPerform + 160
18  CoreData                             0x00000001c4ee01c4 -[NSManagedObjectContext performBlockAndWait:] + 208
19  CoreData                             0x00000001c4ee981c -[NSFetchedResultsController(PrivateMethods) _core_managedObjectContextDidChange:] + 120
20  Foundation                           0x00000001c095106c __57-[NSNotificationCenter addObserver:selector:name:object:]_block_invoke_2 + 24
21  CoreFoundation                       0x00000001c04de99c __CFNOTIFICATIONCENTER_IS_CALLING_OUT_TO_AN_OBSERVER__ + 24
22  CoreFoundation                       0x00000001c04de9ec ___CFXRegistrationPost1_block_invoke + 64
23  CoreFoundation                       0x00000001c04ddce4 _CFXRegistrationPost1 + 392
24  CoreFoundation                       0x00000001c04dd97c ___CFXNotificationPost_block_invoke + 104
25  CoreFoundation                       0x00000001c0456910 -[_CFXNotificationRegistrar find:object:observer:enumerator:] + 1420
26  CoreFoundation                       0x00000001c04dd2ac _CFXNotificationPost + 1264
27  Foundation                           0x00000001c083fbfc -[NSNotificationCenter postNotificationName:object:userInfo:] + 60
28  CoreData                             0x00000001c4eed264 -[NSManagedObjectContext(_NSInternalNotificationHandling) _postObjectsDidChangeNotificationWithUserInfo:] + 512
29  CoreData                             0x00000001c4ee95fc -[NSManagedObjectContext(_NSInternalChangeProcessing) _createAndPostChangeNotification:deletions:updates:refreshes:deferrals:wasMerge:] + 1244
30  CoreData                             0x00000001c4ee886c -[NSManagedObjectContext(_NSInternalChangeProcessing) _processRecentChanges:] + 980
31  CoreData                             0x00000001c501b48c _performRunLoopAction + 376
32  CoreFoundation                       0x00000001c0501524 __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 32
33  CoreFoundation                       0x00000001c04fc1c4 __CFRunLoopDoObservers + 416
34  CoreFoundation                       0x00000001c04fc774 __CFRunLoopRun + 1288
35  CoreFoundation                       0x00000001c04fbf40 CFRunLoopRunSpecific + 476
36  GraphicsServices                     0x00000001ca779534 GSEventRunModal + 104
37  UIKitCore                            0x00000001c4674a60 UIApplicationMain + 1936
38  CJournal                             0x00000001048d8c44 main (main.m:20)
39  libdyld.dylib                        0x00000001c037ae18 start + 0

Может ли кто-нибудь помочь мне найти здесь проблему? Какое "перечисление" я использую, но не вижу? Или что-то еще происходит?

1 ответ

Похоже при изменении координаты MKAnnotationManager наблюдает за изменением, а затем подсчитывает свою хеш-таблицу путем перечисления, и, возможно, вы уже перечисляете аннотации.

В любом случае не следует добавлять в представление объект модели, который нарушает работу MVC. Задача контроллеров - взять модель и отформатировать ее для представления через объект аннотации. Один из подходов - создатьMKPointAnnotationс вашего fetchedObjects (или создать MKPointAnnotationsubclass и инициализируйте его с помощью объекта модели, сохраняя его в слабом свойстве) и добавьте их на карту. В FRCdidChangeObjectвы можете обновить аннотацию из объекта модели. Вид аннотации карты выполняет KVO в координате аннотации, поэтому он автоматически обновляет свое положение на карте. Создайте категорию для объекта модели (см. Документацию) для хранения лениво загруженной аннотации (используяobjc_setAssociatedObject).

Другие вопросы по тегам