문제

I have a core data project. When I do a pull to refresh on the table view, it creates a new context on a background thread, updates the database, and then merges those updates to the main context. Everything was working okay (I think), but now I'm getting the following crash:

2013-09-13 19:01:40.873 My App[2926:a0b] -[__NSCFString controllerWillChangeContent:]: unrecognized selector sent to instance 0xc26b370
2013-09-13 19:02:00.629 My App[2926:a0b] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFString controllerWillChangeContent:]: unrecognized selector sent to instance 0xc26b370'
*** First throw call stack:
(
    0   CoreFoundation                      0x027795e4 __exceptionPreprocess + 180
    1   libobjc.A.dylib                     0x01e888b6 objc_exception_throw + 44
    2   CoreFoundation                      0x02816903 -[NSObject(NSObject) doesNotRecognizeSelector:] + 275
    3   CoreFoundation                      0x0276990b ___forwarding___ + 1019
    4   CoreFoundation                      0x027694ee _CF_forwarding_prep_0 + 14
    5   CoreData                            0x002217b0 -[NSFetchedResultsController(PrivateMethods) _managedObjectContextDidChange:] + 2080
    6   Foundation                          0x015dbe39 __57-[NSNotificationCenter addObserver:selector:name:object:]_block_invoke + 40
    7   CoreFoundation                      0x027d5524 __CFNOTIFICATIONCENTER_IS_CALLING_OUT_TO_AN_OBSERVER__ + 20
    8   CoreFoundation                      0x0272d07b _CFXNotificationPost + 2859
    9   Foundation                          0x01515b91 -[NSNotificationCenter postNotificationName:object:userInfo:] + 98
    10  CoreData                            0x001264a3 -[NSManagedObjectContext(_NSInternalNotificationHandling) _postObjectsDidChangeNotificationWithUserInfo:] + 83
    11  CoreData                            0x0013be96 -[NSManagedObjectContext _mergeChangesFromDidSaveDictionary:usingObjectIDs:] + 3734
    12  CoreData                            0x0013afed -[NSManagedObjectContext mergeChangesFromContextDidSaveNotification:] + 429
    13  My App                            0x0000bc45 -[MAManager updateMainContext:] + 245
    14  libobjc.A.dylib                     0x01e9a81f -[NSObject performSelector:withObject:] + 70
    15  Foundation                          0x0155dc18 __NSThreadPerformPerform + 285
    16  CoreFoundation                      0x027028af __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 15
    17  CoreFoundation                      0x0270223b __CFRunLoopDoSources0 + 235
    18  CoreFoundation                      0x0271f30e __CFRunLoopRun + 910
    19  CoreFoundation                      0x0271eb33 CFRunLoopRunSpecific + 467
    20  CoreFoundation                      0x0271e94b CFRunLoopRunInMode + 123
    21  GraphicsServices                    0x0348e9d7 GSEventRunModal + 192
    22  GraphicsServices                    0x0348e7fe GSEventRun + 104
    23  UIKit                               0x0067b94b UIApplicationMain + 1225
    24  My App                            0x00003442 main + 146
    25  libdyld.dylib                       0x0236d725 start + 0
)
libc++abi.dylib: terminating with uncaught exception of type NSException

Here is the relevant bit of code that it's breaking on:

 // merge changes to main context,fetchedRequestController will automatically monitor the changes and update tableview.
- (void)updateMainContext:(NSNotification *)notification {
    assert([NSThread isMainThread]);
    NSLog(@"Merging changes from context.");
    [[self managedObjectContext] mergeChangesFromContextDidSaveNotification:notification];
    [self save]; // update fetched results controllers
}

// this is called via observing "NSManagedObjectContextDidSaveNotification" from the background thread data load
- (void)mergeChangesFromContextDidSaveNotification:(NSNotification *)notification {
    NSLog(@"Context saved!");
    if (notification.object != [self managedObjectContext]) {
        NSLog(@"Background context propagating to main context.");
        [self performSelectorOnMainThread:@selector(updateMainContext:) withObject:notification waitUntilDone:NO];
    }
}

Does anyone know why I'm getting this error and how to fix it?

도움이 되었습니까?

해결책 3

It seems it was a problem with multiple save requests coming in concurrently (from different managed object contexts, but different threads nonetheless). The solution was to wrap the save operations in a @synchronized block to ensure that the save operations were atomic and did not happen concurrently:

- (void) save {
    // lock and wait if another save operation is in progress
    @synchronized([self class]) {
        NSError *error;
        if (![self save:&error]) {
            NSLog(@"Whoops, couldn't save: %@", error);
        }
    }
}

다른 팁

Some object that is registered for a notification looks to have been released and its address re-used to store a string instead of what's expected.

Turn on zombies for your scheme, run it again, and figure out which object is being sent the notification. Then make sure you're keeping the object alive while you need it.

Your crash is an unrecognized selector with the method [__NSCFString controllerWillChangeContent:]. This method is called on the delegate of a FRC, yet somehow you have the call back performed on an NSString, which doesn't implement that method. Can you post the code where you set up your NSFetchedResultsController in that viewController?

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top