奇怪的Xcode 4.6相关的bug

时间:2013-03-05 00:53:33

标签: ios6 xcode4.6

我们得到的错误是这样的:

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

有时Widget类被发送到那个选择器,有时它是__NSCFString,有时崩溃是这样的:

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

我认为我已经缩小了发生问题的位置,但我不知道为什么这个代码会导致它。 这是我们的数据访问类的示例结构:

// 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

和我们的小部件类

// 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

这是用于获取小部件的代码示例

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
        }
    }
});

这只发生在Xcode 4.6,Release模式中(不在Debug中)。我们在Xcode 4.6发行说明中没有看到任何可以告诉我们发生了什么的线索。

我怀疑这个问题与我们如何构建数据访问类(DataController)以及我们使用类方法来处理Widgets类中的所有数据访问这一事实有关。我怀疑的原因是,当我们从Widgets类中删除类方法并使它们成为实例方法时,摆脱+ initialize方法,并为Widgets类的每个实例设置一个NSManagedObjectContext,问题似乎就出现了程。

只是为了澄清一下,我想我已经解决了这个问题,但是在我理解为什么上面提到的更改修复它之前我不太愿意推出修复程序。它看起来像某种内存问题或糟糕的编程范式,我们没有抓住它。有什么指针吗?

2 个答案:

答案 0 :(得分:0)

原来这是与CLang优化相关的错误。我们发现其他一些人遇到了同样的问题。关闭所有优化似乎可以解决问题。

在我们创建静态数据管理实例,生成新线程以及使用该静态实例创建托管对象上下文时,会发生这种情况。

我们的解决方案是重新考虑我们的数据管理范例。

答案 1 :(得分:-1)

如果您在自己的应用中使用此屏幕,或者出现了几次&第二个崩溃,而不是通过此屏幕检查您的内存管理。当你在内存中保存几个屏幕副本时可能就是这种情况。例如,检查通知中心删除观察员。