Strange Xcode 4.6 related bug

The error we're getting is something like this:

Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[_CDSnapshot_Widget_ unlockObjectStore]: unrecognized selector sent to instance 0x1c5a4350'

sometimes the Widget class is sent that selector, sometimes it's __NSCFString, sometimes the crash is this:

[NSManagedObjectContext unlockObjectStore]: message sent to deallocated instance 0x1ec658c0

I think I've narrowed down where the issue is occurring, but I have no idea why this code would be causing it. Here's an example structure of our data access classes:

// DataController.m
static NSPersistentStoreCoordinator     *_persistentStoreCoordinator;
static NSManagedObjectModel             *_managedObjectModel;
static NSManagedObjectContext           *_mainManagedObjectContext;

@implementation DataController
- (NSManagedObjectContext *) privateManagedObjectContext {
    return [DataController buildManagedObjectContextForConcurrencyType:NSPrivateQueueConcurrencyType];
}

- (NSManagedObjectContext *) defaultManagedObjectContext {
    return [self managedObjectContextForConcurrencyType: self.defaultConcurrencyType];
}

- (NSManagedObjectContext *) managedObjectContextForConcurrencyType: (NSManagedObjectContextConcurrencyType) type {
    if (type == NSMainQueueConcurrencyType)
        return [self mainManagedObjectContext];
    else if (type == NSPrivateQueueConcurrencyType)
        return [self privateManagedObjectContext];

    return nil;
}

// calling _dataController.defaultManagedObjectContext from within the Widgets class
// essentially calls this method for a new context using NSPrivateQueueConcurrencyType as 
// the type parameter
+ (NSManagedObjectContext *) buildManagedObjectContextForConcurrencyType: (NSManagedObjectContextConcurrencyType) type {
    NSManagedObjectContext *context = [[NSManagedObjectContext alloc] initWithConcurrencyType: type];
    [context setUndoManager: nil];
    [context setMergePolicy: NSMergeByPropertyObjectTrumpMergePolicy];
    [context setPersistentStoreCoordinator: _persistentStoreCoordinator];
    return context;
}

@end

and our widgets class

// Widgets.m
static DataController *_dataController;

@implementation Widgets
+ (void) initialize {
    _dataController = [[DataController alloc] init];
}

+ (NSArray *)certainWidgets {
    return [self certainWidgetsInManagedObjectContext:_dataController.defaultManagedObjectContext];
}

+ (NSArray *) certainWidgetsInManagedObjectContext: (NSManagedObjectContext *) context {
    // boiler plate CoreData fetching code
}
@end

This is an example of code used to fetch widgets

dispatch_async(dispatch_get_global_queue(0, 0), ^{
    for (Widget *w in [Widgets certainWidgets]) {
        if ([w.isValid intValue]) {
            // do something extraoridarily fantastic with the widget
        }
    }
});

This only happens in Xcode 4.6, Release mode (not in Debug). We're not seeing anything in the Xcode 4.6 release notes that would give us a clue as to what's happening.

I suspect the issue has to do with how we've structured our data access class (DataController) coupled with the fact that we're using class methods to handle all data access within the Widgets class. The reason for my suspicion is that when we remove the class methods from the Widgets class and make them instance methods instead, get rid of the +initialize method, and set up an NSManagedObjectContext for each instance of the Widgets class, the problem seems to go away.

Just to clarify, I think I've fixed the issue, but I'm not comfortable pushing out the fix until I understand why the above mentioned changes fix it. It looks like there's some sort of memory issue or bad programming paradigm that we're not catching onto. Any pointers?


Turns out this is a bug related to CLang optimizations. We've found a few other people experiencing the same problem. Turning all optimizations off seems to fix the issue.

It happens, for us, when creating a static data management instance, spawning a new thread, and using that static instance to create a managed object context.

Our fix will be to rethink our data management paradigm.


If you're using this screen over your app, or it appears several time & crashes on second one than check your memory management over this screen. It may be the case, when you're holding in memory several copies of screen. Check notification centre removal observer for example.

链接地址: http://www.djcxy.com/p/68680.html

上一篇: Xcode 4.6.1调试器本地变量不可用

下一篇: 奇怪的Xcode 4.6相关的错误