奇怪的Xcode 4.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,问题似乎就此消失远。
只是为了澄清,我认为我已经解决了这个问题,但我不愿意推出修复程序,直到我明白为什么上述修改能够修复它。 看起来好像存在着某种内存问题或者糟糕的编程范例,我们没有注意到。 任何指针?
原来这是一个与CLang优化相关的错误。 我们发现一些其他人遇到同样的问题。 关闭所有优化似乎解决了这个问题。
对于我们来说,创建一个静态数据管理实例,产生一个新的线程,并使用该静态实例创建一个托管对象上下文。
我们的解决方案将是重新思考我们的数据管理范例。
如果您在应用程序中使用此屏幕,或者第二次出现时出现多次崩溃问题,请通过此屏幕检查您的内存管理。 可能是这种情况,当你在内存中保存好几个屏幕副本。 例如,检查通知中心删除观察者。
链接地址: http://www.djcxy.com/p/68679.html