使用 Core Data 和 iCloud 添加持久存储时涉及 PFUbiquityPeer 的异常

Posted

技术标签:

【中文标题】使用 Core Data 和 iCloud 添加持久存储时涉及 PFUbiquityPeer 的异常【英文标题】:Exception with PFUbiquityPeer involved when adding a persistent store with Core Data & iCloud 【发布时间】:2012-02-19 14:23:06 【问题描述】:

当我使用NSPersistentStoreUbiquitousContentNameKeyNSPersistentStoreUbiquitousContentURLKey 添加持久性存储时,我的应用程序每秒钟都会崩溃一次,但出现异常。这发生在调用addPersistentStoreWithType:configuration:URL:options:error:

堆栈跟踪如下所示:

*** Terminating app due to uncaught exception 'NSInvalidArgumentException',
  reason: 'An NSManagedObject of class 'PFUbiquityPeer' must have a valid
  NSEntityDescription.'
*** First throw call stack:
(
     0   CoreFoundation   0x00007fff8b35ffc6 __exceptionPreprocess + 198
     1   libobjc.A.dylib  0x00007fff83368d5e objc_exception_throw + 43
     2   CoreData         0x00007fff82c28c06 -[NSManagedObject initWithEntity:insertIntoManagedObjectContext:] + 182
     3   CoreData         0x00007fff82d4d3dc +[PFUbiquityPeer(UbiquityMethods) peerForPeerID:inManagedObjectContext:createIfMissing:] + 364
     4   CoreData         0x00007fff82d4f809 -[PFUbiquityPeerRange(UbiquityMethods) loadFromStoreMetadataDictionary:] + 105
     5   CoreData         0x00007fff82d80372 -[PFUbiquityStoreMetadataMedic recoverPeerRangesWithError:] + 418
     6   CoreData         0x00007fff82d80ab5 -[PFUbiquityStoreMetadataMedic recoverMetadataWithError:] + 1749
     7   CoreData         0x00007fff82d831dc -[PFUbiquitySetupAssistant performPostStoreSetupWithStore:error:] + 732
     8   CoreData         0x00007fff82c04001 -[NSPersistentStoreCoordinator addPersistentStoreWithType:configuration:URL:options:error:] + 3537
     9   MyApp            0x000000010323de60 -[AppDelegate persistentStoreCoordinator] + 4224
     10  MyApp            0x000000010323e43f -[AppDelegate managedObjectContext] + 95
     11  Foundation       0x00007fff863b5384 _NSGetUsingKeyValueGetter + 62
     12  Foundation       0x00007fff863b5339 -[NSObject(NSKeyValueCoding) valueForKey:] + 392
     13  Foundation       0x00007fff863d4dc6 -[NSObject(NSKeyValueCoding) valueForKeyPath:] + 348
     14  AppKit           0x00007fff87fb1ae2 -[NSBinder _valueForKeyPath:ofObject:mode:raisesForNotApplicableKeys:] + 654
     15  AppKit           0x00007fff87fb17cc -[NSBinder valueForBinding:resolveMarkersToPlaceholders:] + 171
     16  AppKit           0x00007fff87fb143a -[NSObjectParameterBinder _updateObject:observedController:observedKeyPath:context:] + 1181
     17  AppKit           0x00007fff87fa3777 -[NSObject(NSKeyValueBindingCreation) bind:toObject:withKeyPath:options:] + 591
     18  AppKit           0x00007fff87f9ca89 -[NSIBObjectData nibInstantiateWithOwner:topLevelObjects:] + 1079
     19  AppKit           0x00007fff87f9309f loadNib + 322
     20  AppKit           0x00007fff87f9259c +[NSBundle(NSNibLoading) _loadNibFile:nameTable:withZone:ownerBundle:] + 217
     21  AppKit           0x00007fff87f924b7 +[NSBundle(NSNibLoading) loadNibFile:externalNameTable:withZone:] + 141
     22  AppKit           0x00007fff87f923fa +[NSBundle(NSNibLoading) loadNibNamed:owner:] + 364
     23  AppKit           0x00007fff882059b3 NSApplicationMain + 398
     24  MyApp            0x0000000103239522 main + 34
     25  MyApp            0x00000001032394f4 start + 52
     26  ???              0x0000000000000003 0x0 + 3
)
terminate called throwing an exception(lldb)

当我不向商店添加 NSPersistentStoreUbiquitousContentNameKeyNSPersistentStoreUbiquitousContentURLKey 选项时,一切正常。我仅在每第二个应用程序启动时才收到此异常。出于测试目的(并且因为我认为该问题可能与并发有关),我从主 NIB 文件中删除了所有核心数据访问和绑定,并尝试在 applicationDidFinishLaunching: 方法中以编程方式访问核心数据堆栈。在第一次测试中我直接执行此操作,第二次在延迟 10 秒后执行选择器 (managedObjectContext)。两次测试都会在应用程序启动时产生相同的异常。

(在此示例中略短)managedObjectContext 方法如下所示:

- (NSManagedObjectContext *)managedObjectContext

  if (managedObjectContext_)
  
    return managedObjectContext_;
  

  NSPersistentStoreCoordinator *coordinator = self.persistentStoreCoordinator;
  if (!coordinator)
  
    return nil;
  

  NSManagedObjectContext *moc = [[NSManagedObjectContext alloc] 
    initWithConcurrencyType:NSMainQueueConcurrencyType];
  [moc performBlockAndWait:
   ^
    moc.mergePolicy = [[NSMergePolicy alloc] 
      initWithMergeType:NSMergeByPropertyObjectTrumpMergePolicyType];
    [moc setPersistentStoreCoordinator:coordinator];

    [[NSNotificationCenter defaultCenter] addObserver:self
      selector:@selector(mergeChangesFrom_iCloud:) 
      name:NSPersistentStoreDidImportUbiquitousContentChangesNotification 
      object:coordinator];
  ];
  managedObjectContext_ = moc;

  return managedObjectContext_;

persistentStoreCoordinator的相关部分是:

  NSMutableDictionary *storeOptions = [NSMutableDictionary dictionary];
  [storeOptions setObject:[NSNumber numberWithBool:YES] 
    forKey:NSMigratePersistentStoresAutomaticallyOption];
  [storeOptions setObject:[NSNumber numberWithBool:YES] 
    forKey:NSInferMappingModelAutomaticallyOption];

  NSURL *url = [NSURL fileURLWithPath:[applicationSupportDirectory 
    stringByAppendingPathComponent:kJCMyAppDatabaseFilename]];
  NSURL *ubiquityURL = [[NSFileManager defaultManager] 
    URLForUbiquityContainerIdentifier:nil];
  if (ubiquityURL)
  
    JCDLog(@"User has iCloud enabled.");
    [storeOptions setObject:@"com.juicycocktail.myapp" 
      forKey:NSPersistentStoreUbiquitousContentNameKey];
    [storeOptions setObject:[NSURL fileURLWithPath:[[ubiquityURL path] 
      stringByAppendingPathComponent:kJCMyAppDatabaseFilename]] 
      forKey:NSPersistentStoreUbiquitousContentURLKey];       
  

  persistentStoreCoordinator_ = [[NSPersistentStoreCoordinator alloc] 
    initWithManagedObjectModel:mom];
  NSPersistentStoreCoordinator *psc = persistentStoreCoordinator_;

  dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),
  (dispatch_block_t)^
    [psc lock];
    if (![psc addPersistentStoreWithType:kJCMyAppStoreType
      configuration:nil URL:url options:storeOptions error:&error])
    
      dispatch_async(dispatch_get_main_queue(),
      ^
        [[NSApplication sharedApplication] presentError:error];
        persistentStoreCoordinator_ = nil;

        return;
      );
        
    [psc unlock];

    dispatch_async(dispatch_get_main_queue(),
    ^
      JCDLog(@"asynchronously added persistent store!");
      [[NSNotificationCenter defaultCenter]
        postNotificationName:@"RefetchAllDatabaseData"
        object:self userInfo:nil];
    );
  );

  return persistentStoreCoordinator_;

我猜 PFUbiquityPeer 类可能与保存在 iCloud 移动文档文件夹中的 Core Data 事务日志有关,但我仍然找不到这个问题的真正原因。非常感谢任何帮助如何跟踪此异常的根源,因为我已经疯了。特别是解决方法甚至解决方案对我很有帮助。如果有人提示如何至少追踪此异常,我也很高兴。

注意:我还提交了一个错误,以防这是一个 API 错误 (rdar://10892613)。

【问题讨论】:

【参考方案1】:

重新启动 OS X 解决了这个问题。这让我想起了IT Crowd running gag。

【讨论】:

哇,我重新启动了计算机,它也工作了!在重新启动之前,我的代码将在我将 NSPersistentStoreUbiquitousContentNameKey 添加到 migratePersistentStore 方法的位置停止

以上是关于使用 Core Data 和 iCloud 添加持久存储时涉及 PFUbiquityPeer 的异常的主要内容,如果未能解决你的问题,请参考以下文章

处理 iCloud Core Data 错误

将 Core Data 应用程序迁移到 iCloud

Core Data、iCloud 和两个持久性存储失败

Swift - 向 Core Data 添加启用 iCloud 的持久存储

iOS Core Data iCloud 同步 - 可选

iOS 7 中的 iCloud、Core Data 和来自 Web 服务的数据