在主线程中非法访问托管对象上下文,为什么?
Illegal access to managed object context in main thread, why?
我已经启用 com.apple.CoreData.ConcurrencyDebug 1
检查 Core Data
并发错误。我在 Swift
class:
中有以下代码片段
lazy var context: NSManagedObjectContext! = {
var appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
return appDelegate.managedObjectContext!
}()
func getAllEntitiesToRootContext() -> [MyEntity]? {
let fetchRequest = NSFetchRequest(entityName:"MyEntity")
do {
let fetchedResults = try context.executeFetchRequest(fetchRequest) as! [MyEntity]
if fetchedResults.count > 0 {
return fetchedResults
} else {
return nil
}
} catch let error as NSError {
print("could not fetch \(error), \(error.userInfo)")
return nil
}
}
如果我没理解错的话,我从 AppDelegate
获得的上下文与主线程相关联,对吧?
但是,从另一个 Objective-C
class 我有,我有:
self.myEntitiesArray = [mySwiftClass getAllEntitiesToRootContext];
我得到了这个错误日志:
CoreData: error: The current thread is not the recognized owner of this NSManagedObjectContext(0x1a25f8a0). Illegal access during executeFetchRequest:error:
我不明白为什么...我应该将这样的上下文关联到主线程,并且我正在从主线程调用 getAllEntitiesToRootContext
...
拜托,我需要帮助。提前致谢
编辑:这些是AppDelegate
中与Core Data
相关的方法:
- (NSManagedObjectContext *)managedObjectContext
{
// Returns the managed object context for the application (which is already bound to the persistent store coordinator for the application.)
if (_managedObjectContext != nil) {
return _managedObjectContext;
}
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (!coordinator) {
return nil;
}
_managedObjectContext = [[NSManagedObjectContext alloc] init];
[_managedObjectContext setPersistentStoreCoordinator:coordinator];
return _managedObjectContext;
}
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
// The persistent store coordinator for the application. This implementation creates and return a coordinator, having added the store for the application to it.
if (_persistentStoreCoordinator != nil) {
return _persistentStoreCoordinator;
}
// Create the coordinator and store
_persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"MyApp.sqlite"];
NSError *error = nil;
NSString *failureReason = @"There was an error creating or loading the application's saved data.";
if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) {
// Report any error we got.
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
dict[NSLocalizedDescriptionKey] = @"Failed to initialize the application's saved data";
dict[NSLocalizedFailureReasonErrorKey] = failureReason;
dict[NSUnderlyingErrorKey] = error;
error = [NSError errorWithDomain:@"YOUR_ERROR_DOMAIN" code:9999 userInfo:dict];
// Replace this with code to handle the error appropriately.
// abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
}
return _persistentStoreCoordinator;
}
- (NSManagedObjectModel *)managedObjectModel
{
// The managed object model for the application. It is a fatal error for the application not to be able to find and load its model.
if (_managedObjectModel != nil) {
return _managedObjectModel;
}
NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"MyApp" withExtension:@"momd"];
_managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
return _managedObjectModel;
}
编辑 2: 我正在使用 Xcode 7
并在 iOS 9
设备中进行测试。
编辑 3: 如果我禁用 com.apple.CoreData.ConcurrencyDebug 1
,我从 getAllEntitiesToRootContext()
获取对象...我真的什么都不懂,这是为什么发生了什么?
编辑 4: 我做了一些测试。如果我从 Objective-C
class:
- (void)getEntities
{
AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
NSManagedObjectContext *mainContext = appDelegate.managedObjectContext;
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:@"MyEntity"];
NSArray *entities = [mainContext executeFetchRequest:fetchRequest error:nil];
for (NSManagedObject *item in entities) {
NSLog(@"Name: %@", ((MyEntity *)item).name);
}
}
我有时在调用 executeFetchRequest
时不会出错,并且实体的名称会显示在日志控制台中。其他时候,我也会遇到与我在上面发布的类似的核心数据错误,而且我在做我正在做的事情时也会遇到:
- (NSArray *)getEntities
{
MyEntityDao *myEntityDao = [[MyEntityDao alloc] init];
self.myEntities = [[myEntityDao getAllEntitiesToRootContext] mutableCopy];
return [[NSArray arrayWithArray:self.myEntities] copy];
}
其中 MyEntityDao
是定义 lazy var context
和 getAllEntitiesToRootContext()
的 Swift
class,我得到了我也在上面发布的核心数据错误...为什么?这两个代码片段不是等价的吗?为什么我有时会说主线程不是我从 AppDelegate
检索到的 MOC 的所有者?
我真的需要帮助...
context.executeFetchRequest(fetchRequest)
是做什么的?该代码是什么样的?
有时您在主队列之外的另一个队列中。
您收到的错误表明您违反了线程限制。如果您在 Xcode 中有异常和错误断点,它将向您显示违反规则的确切代码行以及它在哪个队列上执行。
Xcode停在哪一行代码?
Xcode 停止时你在哪个队列?
我不建议关闭该调试标志,它可以帮助您并让您发现线程错误。关闭它只是隐藏了问题,并且会在生产中导致用户数据出现问题。最好投入时间,了解正在发生的事情并正确纠正它。
似乎在调用 getAllEntitiesToRootContext()
之前,在某些情况下我正在从不是主线程的队列中检索 AppDelegate
中定义的上下文,是什么导致该上下文被初始化在另一个队列中...
感谢 Leo 的评论和 Marcus S. Zarra 的回答,我找到了这个,谢谢。
我已经启用 com.apple.CoreData.ConcurrencyDebug 1
检查 Core Data
并发错误。我在 Swift
class:
lazy var context: NSManagedObjectContext! = {
var appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
return appDelegate.managedObjectContext!
}()
func getAllEntitiesToRootContext() -> [MyEntity]? {
let fetchRequest = NSFetchRequest(entityName:"MyEntity")
do {
let fetchedResults = try context.executeFetchRequest(fetchRequest) as! [MyEntity]
if fetchedResults.count > 0 {
return fetchedResults
} else {
return nil
}
} catch let error as NSError {
print("could not fetch \(error), \(error.userInfo)")
return nil
}
}
如果我没理解错的话,我从 AppDelegate
获得的上下文与主线程相关联,对吧?
但是,从另一个 Objective-C
class 我有,我有:
self.myEntitiesArray = [mySwiftClass getAllEntitiesToRootContext];
我得到了这个错误日志:
CoreData: error: The current thread is not the recognized owner of this NSManagedObjectContext(0x1a25f8a0). Illegal access during executeFetchRequest:error:
我不明白为什么...我应该将这样的上下文关联到主线程,并且我正在从主线程调用 getAllEntitiesToRootContext
...
拜托,我需要帮助。提前致谢
编辑:这些是AppDelegate
中与Core Data
相关的方法:
- (NSManagedObjectContext *)managedObjectContext
{
// Returns the managed object context for the application (which is already bound to the persistent store coordinator for the application.)
if (_managedObjectContext != nil) {
return _managedObjectContext;
}
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (!coordinator) {
return nil;
}
_managedObjectContext = [[NSManagedObjectContext alloc] init];
[_managedObjectContext setPersistentStoreCoordinator:coordinator];
return _managedObjectContext;
}
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
// The persistent store coordinator for the application. This implementation creates and return a coordinator, having added the store for the application to it.
if (_persistentStoreCoordinator != nil) {
return _persistentStoreCoordinator;
}
// Create the coordinator and store
_persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"MyApp.sqlite"];
NSError *error = nil;
NSString *failureReason = @"There was an error creating or loading the application's saved data.";
if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) {
// Report any error we got.
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
dict[NSLocalizedDescriptionKey] = @"Failed to initialize the application's saved data";
dict[NSLocalizedFailureReasonErrorKey] = failureReason;
dict[NSUnderlyingErrorKey] = error;
error = [NSError errorWithDomain:@"YOUR_ERROR_DOMAIN" code:9999 userInfo:dict];
// Replace this with code to handle the error appropriately.
// abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
}
return _persistentStoreCoordinator;
}
- (NSManagedObjectModel *)managedObjectModel
{
// The managed object model for the application. It is a fatal error for the application not to be able to find and load its model.
if (_managedObjectModel != nil) {
return _managedObjectModel;
}
NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"MyApp" withExtension:@"momd"];
_managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
return _managedObjectModel;
}
编辑 2: 我正在使用 Xcode 7
并在 iOS 9
设备中进行测试。
编辑 3: 如果我禁用 com.apple.CoreData.ConcurrencyDebug 1
,我从 getAllEntitiesToRootContext()
获取对象...我真的什么都不懂,这是为什么发生了什么?
编辑 4: 我做了一些测试。如果我从 Objective-C
class:
- (void)getEntities
{
AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
NSManagedObjectContext *mainContext = appDelegate.managedObjectContext;
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:@"MyEntity"];
NSArray *entities = [mainContext executeFetchRequest:fetchRequest error:nil];
for (NSManagedObject *item in entities) {
NSLog(@"Name: %@", ((MyEntity *)item).name);
}
}
我有时在调用 executeFetchRequest
时不会出错,并且实体的名称会显示在日志控制台中。其他时候,我也会遇到与我在上面发布的类似的核心数据错误,而且我在做我正在做的事情时也会遇到:
- (NSArray *)getEntities
{
MyEntityDao *myEntityDao = [[MyEntityDao alloc] init];
self.myEntities = [[myEntityDao getAllEntitiesToRootContext] mutableCopy];
return [[NSArray arrayWithArray:self.myEntities] copy];
}
其中 MyEntityDao
是定义 lazy var context
和 getAllEntitiesToRootContext()
的 Swift
class,我得到了我也在上面发布的核心数据错误...为什么?这两个代码片段不是等价的吗?为什么我有时会说主线程不是我从 AppDelegate
检索到的 MOC 的所有者?
我真的需要帮助...
context.executeFetchRequest(fetchRequest)
是做什么的?该代码是什么样的?
有时您在主队列之外的另一个队列中。
您收到的错误表明您违反了线程限制。如果您在 Xcode 中有异常和错误断点,它将向您显示违反规则的确切代码行以及它在哪个队列上执行。
Xcode停在哪一行代码?
Xcode 停止时你在哪个队列?
我不建议关闭该调试标志,它可以帮助您并让您发现线程错误。关闭它只是隐藏了问题,并且会在生产中导致用户数据出现问题。最好投入时间,了解正在发生的事情并正确纠正它。
似乎在调用 getAllEntitiesToRootContext()
之前,在某些情况下我正在从不是主线程的队列中检索 AppDelegate
中定义的上下文,是什么导致该上下文被初始化在另一个队列中...
感谢 Leo 的评论和 Marcus S. Zarra 的回答,我找到了这个,谢谢。