ios - 在主线程中非法访问托管对象上下文,为什么?

标签 ios multithreading core-data concurrency nsmanagedobjectcontext

我已启用 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: 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 类执行此操作:

- (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 contextgetAllEntitiesToRootContext()Swift类,我得到了核心数据错误我也在上面发布了......为什么?这两个代码片段不是等价的吗?为什么有时有人说主线程不是我从 AppDelegate 检索的 MOC 的所有者?

我真的需要帮助......

最佳答案

context.executeFetchRequest(fetchRequest) 的作用是什么?该代码是什么样的?

在某些时候,您位于主队列以外的另一个队列中。

您收到的错误表明您违反了线程限制。如果您在 Xcode 中的异常和错误上有断点,它将显示违反规则的确切代码行以及它在哪个队列上执行。

Xcode 停止在哪一行代码上?

当 Xcode 停止时,您处于哪个队列?

我不建议关闭该调试标志,它可以帮助您并让您找到线程错误。关闭它只是隐藏问题,并且会导致生产和用户数据出现问题。最好投入时间,了解发生了什么并正确纠正。

关于ios - 在主线程中非法访问托管对象上下文,为什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32774538/

相关文章:

iOS-MagicalRecord/AFNetworking/NSFetchedResultsController-后台重新同步过程导致永久挂起

swift - 在核心数据中保存小数和货币

ios - 如何在 ImageIO iOS 框架中升级图像?

iphone - 如何找到天数

ios - 线程 1 : EXC_BAD_ACCESS (code=EXC_I386_GPFLT)

.net - 如何结束线程或将其加入主线程

python - 多线程 Python 代码中的 Emacs pdb 和断点问题

java - 在调用 removeCallbacks() 时,在新线程上启动的可运行对象不会停止

ios - 创建图像的.Zip文件

ios - 在 Core Data 中分离单个对象模型的组件