在主线程中非法访问托管对象上下文,为什么?
我已启用com.apple.CoreData.ConcurrencyDebug 1
来检查Core Data
并发错误。 我在Swift
类中有以下代码片段:
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
课程中,我做到了:
self.myEntitiesArray = [mySwiftClass getAllEntitiesToRootContext];
我收到此错误日志:
CoreData:错误:当前线程不是此NSManagedObjectContext(0x1a25f8a0)的已识别所有者。 executeFetchRequest期间非法访问:错误:
我不明白为什么……我应该有这样的上下文与主线程关联,我从主线程调用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
类中执行此操作:
- (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
时没有错误,并且日志控制台中显示了实体的名称。 其他时候我也得到了类似于我上面发布的Core Data错误,我在做的时候也得到了:
- (NSArray *)getEntities { MyEntityDao *myEntityDao = [[MyEntityDao alloc] init]; self.myEntities = [[myEntityDao getAllEntitiesToRootContext] mutableCopy]; return [[NSArray arrayWithArray:self.myEntities] copy]; }
其中MyEntityDao
是定义lazy var context
和getAllEntitiesToRootContext()
的Swift
类,我得到了我上面发布的Core Data错误…为什么? 这两个代码片段不相同吗? 为什么我有时会说主线程不是我从AppDelegate
检索的MOC的所有者?
我真的需要帮助…
context.executeFetchRequest(fetchRequest)
什么作用? 那段代码是什么样的?
在某些时候,您处于主队列以外的另一个队列中。
您收到的错误表明您违反了线程限制。 如果您在Xcode中有exception和错误的断点,它将显示违反规则的确切代码行以及执行的队列。
什么代码行是Xcode停止的?
当Xcode停止时你在哪个队列?
我不建议关闭调试标志,它可以帮助您并让您找到线程错误。 关闭它只是隐藏问题,并将导致生产中的问题与用户数据。 更好地投入时间,了解正在发生的事情并正确地纠正它。
似乎在调用getAllEntitiesToRootContext()
之前,在某些情况下我从一个不是主线程的队列中检索AppDelegate
中定义的上下文,导致该上下文在该另一个队列中初始化的原因…
我感谢Leo的评论和Marcus S. Zarra的回答,谢谢。