2015-09-01 63 views
11

我有一個適用於OSX和iOS的應用程序,它們都使用iCloud在它們之間共享核心數據。當我在iPhone上進行更改時,我可以在OSX應用程序中看到它們,並且在兩個應用程序都調用NSPersistentStoreDidImportUbiquitousContentChangesNotification,所以iOS - > Mac運行良好。但是,當我在Mac應用程序中進行一些更改時,我無法在iPhone中看到它們。 iPhone從不會呼叫NSPersistentStoreDidImportUbiquitousContentChangesNotification。我可以改變Mac的唯一方法是在iPhone上做一些改變。然後我可以看到所有的變化。iCloud Core OSX和iOS之間的數據共享

兩個項目中的iCloud集成是一樣的。核心數據數據模型是相同的。權利也是相同的。

我所有的代碼是基於這個庫:http://ossh.com.au/design-and-technology/software-development/sample-library-style-ios-core-data-app-with-icloud-integration/

爲什麼沒有得到蘋果的變化,直到我在做一些iPhone改變iPhone?有任何想法嗎?

另一個問題

在我的應用程序,當用戶啓用iCloud的我檢查,如果已經在iCloud中的文件。如果存在文件,用戶可以選擇從iCloud文件恢復核心數據或從本地存儲中啓動新的副本。 要開始一個新的副本我使用此代碼:

- (void)startNewCopy 
{ 
    [self removeICloudStore]; 
    [self moveStoreToIcloud]; 
} 

- (void)removeICloudStore 
{ 
    BOOL result; 
    NSError *error; 
    // Now delete the iCloud content and file 
    result = [NSPersistentStoreCoordinator removeUbiquitousContentAndPersistentStoreAtURL:[self icloudStoreURL] 
                      options:[self icloudStoreOptions] 
                      error:&error]; 
    if (!result) 
    { 
     NSLog(@"Error removing store"); 
    } 
    else 
    { 
     NSLog(@"Core Data store removed."); 
     // Now delete the local file 
     [self deleteLocalCopyOfiCloudStore]; 
    } 

} 


- (void)deleteLocalCopyOfiCloudStore { 
    // We need to get the URL to the store 
    NSError *error = nil; 
    [[NSFileManager defaultManager] removeItemAtURL:[self localUbiquitySupportURL] error:&error]; 
} 

- (void)moveStoreToIcloud 
{ 
    // Open the store 
    NSPersistentStore *sourceStore = [[_persistentStoreCoordinator persistentStores] firstObject]; 

    if (!sourceStore) 
    { 
     NSLog(@" failed to add old store"); 
    } 
    else 
    { 
     NSLog(@" Successfully added store to migrate"); 
     NSError *error; 
     id migrationSuccess = [_persistentStoreCoordinator migratePersistentStore:sourceStore toURL:[self icloudStoreURL] options:[self icloudStoreOptions] withType:NSSQLiteStoreType error:&error]; 

     if (migrationSuccess) 
     { 
      NSLog(@"Store migrated to iCloud"); 

      _persistentStoreCoordinator = nil; 
      _managedObjectContext = nil; 

      // Now delete the local file 
      [self deleteLocalStore]; 

     } 
     else 
     { 
      NSLog(@"Failed to migrate store: %@, %@", error, error.userInfo); 

     } 
    } 

} 

- (void)deleteLocalStore 
{ 
    NSError *error = nil; 
    [[NSFileManager defaultManager] removeItemAtURL:[self localStoreURL] error:&error]; 
} 

從一個單一的設備中的所有似乎運作良好這樣做,但當我嘗試這個連接多個設備,我得到了一些錯誤。

例如:

我有兩個設備。第一個連接到iCloud,第二個連接到iCloud。 在第一個設備時啓用iCloud的我選擇startNewCopy,然後在第二設備我得到這個錯誤:

CoreData: Ubiquity: Librarian returned a serious error for starting downloads Error Domain=BRCloudDocsErrorDomain Code=5 "The operation couldn’t be completed. (BRCloudDocsErrorDomain error 5 - No document at URL)"

NSPersistentStoreCoordinatorStoresDidChangeNotification錯誤之前不會被調用。

這是我的通知代碼:

- (void)processStoresDidChange:(NSNotification *)notification 
{ 
     NSLog(@"processStoresDidChange"); 
     // Post notification to trigger UI updates 

     // Check type of transition 
     NSNumber *type = [notification.userInfo objectForKey:NSPersistentStoreUbiquitousTransitionTypeKey]; 

     //NSLog(@" userInfo is %@", notification.userInfo); 
     //NSLog(@" transition type is %@", type); 

     if (type.intValue == NSPersistentStoreUbiquitousTransitionTypeInitialImportCompleted) { 

      NSLog(@" transition type is NSPersistentStoreUbiquitousTransitionTypeInitialImportCompleted"); 

     } else if (type.intValue == NSPersistentStoreUbiquitousTransitionTypeAccountAdded) { 
      NSLog(@" transition type is NSPersistentStoreUbiquitousTransitionTypeAccountAdded"); 
     } else if (type.intValue == NSPersistentStoreUbiquitousTransitionTypeAccountRemoved) { 
      NSLog(@" transition type is NSPersistentStoreUbiquitousTransitionTypeAccountRemoved"); 
     } else if (type.intValue == NSPersistentStoreUbiquitousTransitionTypeContentRemoved) { 
      NSLog(@" transition type is NSPersistentStoreUbiquitousTransitionTypeContentRemoved"); 
     } 

     [[NSOperationQueue mainQueue] addOperationWithBlock:^ { 

      if (type.intValue == NSPersistentStoreUbiquitousTransitionTypeContentRemoved) { 

       [self deleteLocalStore]; 
       _persistentStoreCoordinator = nil; 
       _managedObjectContext = nil; 

       NSLog(@" iCloud store was removed! Wait for empty store"); 
      } 

      // Refresh user Interface 
      [[NSNotificationCenter defaultCenter] postNotificationName:@"notiIcloud" object:@"storeChanged"]; 
     }]; 

} 

我怎樣才能檢測到iCloud的內容已被刪除,避免收到上述錯誤?

+0

這並不能真正回答你的問題,但是我很久以前就放棄了在iCloud支持上使用Core Data。然後我寫了我自己的同步,但它有點有限。然後我發現了Ensembles(http://www.ensembles.io)並且一直使用它。這對我來說真棒。有一個免費的開源版本。 –

+0

Thx爲答案,但我更喜歡使用蘋果的標準iCloud支持。 – user3065901

+0

祝你好運! –

回答

0

在我看來,你可能沒有使用適當的接口。

您可以在不使用NSPersistentStore方法的情況下將文件移入和移出iCloud。 通常,相應的操作也必須包含在NSFileCoordinator調用中。

這是我在iOS上做的。 toLocal表示此舉或從本地(設備)存儲:

// 
/// Move file between stores (assumed no name clash). 
/// Return new URL. 
/// Note: cloud file moves are asynchronous. 
/// 
- (NSURL *)moveStoreFile:(NSURL *)url toRootURL:(NSURL *)rootURL toLocal:(BOOL)toLocal 
{ 
    NSURL *newURL = rootURL; 
    if (!toLocal) 
     newURL = [newURL URLByAppendingPathComponent:@"Documents"]; 
    newURL = [newURL URLByAppendingPathComponent:url.lastPathComponent]; 

    [self backupFile:url isLocal:!toLocal completionHandler: 
    ^(BOOL success) { 

     MRLOG(@"MOVE %s %@ to %s %@", toLocal? "icloud" : "local", [url lastPathComponent], 
       toLocal? "local" : "icloud", [newURL lastPathComponent]); 

     dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), 
     ^{ 
      NSError *error; 
      // setUbiquitous does file coordination 
      BOOL msuccess = [[NSFileManager defaultManager] 
          setUbiquitous:!toLocal itemAtURL:url destinationURL:newURL error:&error]; 

      dispatch_async(dispatch_get_main_queue(), 
      ^{ 
       if (!msuccess) 
        MRLOG(@"move failed: %@", error); 
       [self.delegate moveStoreFileCompletedWithStatus:success error:error]; 
      }); 
     }); 
    }]; 

    return newURL; 
} 

刪除需要明確的文件協調:

/// 
/// Purge backup file (really delete it). 
/// Note: cloud deletes are asynchronous. 
/// 
- (void)purgeFile:(NSURL *)url isLocal:(BOOL)isLocal 
{ 
    MRLOG(@"PURGE %s %@", isLocal? "local" : "icloud", [url lastPathComponent]); 

    if (isLocal) 
     [self removeFile:url]; 
    else 
     dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), 
     ^{ 
      NSError *coordinationError; 
      NSFileCoordinator *coordinator = [[NSFileCoordinator alloc] initWithFilePresenter:nil]; 

      [coordinator coordinateWritingItemAtURL:url options:NSFileCoordinatorWritingForDeleting 
                error:&coordinationError 
            byAccessor: 
      ^(NSURL* writingURL) 
      { 
       [self removeFile:writingURL]; 
      }]; 
      if (coordinationError) { 
       MRLOG(@"coordination error: %@", coordinationError); 
       [(SSApplication *)[SSApplication sharedApplication] fileErrorAlert:coordinationError]; 
      } 
     }); 
} 

要檢測的變化,你需要使用NSMetadataQuery並添加觀察員NSMetadataQueryDidUpdateNotification文件。

0

我有一個類似的問題,同步iOS與我的Mac。

這個錯誤5實際上意味着您的商店存在問題。

你可以嘗試以下步驟:

  • 在iOS您需要重置模擬器的內容,並且還(僅適用於您的應用程序)清除您的iCloud內容。

你可以通過調用重置您的iCloud內容(抱歉,我有它在SWIFT):

try! NSPersistentStoreCoordinator.removeUbiquitousContentAndPersistentStoreAtURL(storeURL, options: self.options) 
  • 在Mac OS您需要刪除該文件夾的內容「CoreDataUbiquitySupport/YourAppId「。這基本上是您的核心數據持久性存儲(例如:SQLite文件)。

當Model(xcdatamodeld文件)發生更改並且現有數據尚未清除時,會發生此問題。您最終將擁有與舊版本模型生成的數據關聯的新模型,並且您試圖同步混合跨設備的數據...

未來,要避免與Model相關的問題,請查看Core Data Model Versioning和數據遷移。 https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/CoreDataVersioning/Articles/Introduction.html

希望它能解決您的問題。