[英]iCloud Core Data sharing between OSX and iOS
我有一個OSX和iOS的應用程序,都使用iCloud在它們之間共享核心數據。 當我在iPhone中進行更改時,我可以在OSX應用程序中看到它們,並在兩個應用程序中調用NSPersistentStoreDidImportUbiquitousContentChangesNotification
,因此iOS - > Mac運行良好。 但是當我在Mac應用程序中進行一些更改時,我無法在iPhone中看到它們。 iPhone從不調用NSPersistentStoreDidImportUbiquitousContentChangesNotification
。 我能改變Mac的唯一方法是在iPhone上做一些改變。 然后我可以看到所有的變化。
兩個項目中的iCloud集成是一樣的。 核心數據數據模型是相同的。 權利也是一樣的。
我的所有代碼都基於這個庫: http : //ossh.com.au/design-and-technology/software-development/sample-library-style-ios-core-data-app-with-icloud-integration/
為什么在我在iPhone上做一些改變之前iPhone沒有改變Mac? 有任何想法嗎?
另一個問題
在我的應用程序中,當用戶啟用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在開始下載時返回了一個嚴重錯誤錯誤Domain = BRCloudDocsErrorDomain Code = 5“操作無法完成。(BRCloudDocsErrorDomain錯誤5 - 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內容已被刪除並避免上述錯誤?
在我看來,你可能沒有使用適當的接口。
您可以在不使用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
添加觀察NSMetadataQueryDidUpdateNotification
。
我有一個類似的問題將iOS與我的Mac同步。
此錯誤5實際上意味着您的商店存在問題。
您可以嘗試以下步驟:
你可以通過調用重置你的iCloud內容(對不起,我在Swift中有它):
try! NSPersistentStoreCoordinator.removeUbiquitousContentAndPersistentStoreAtURL(storeURL, options: self.options)
當Model(xcdatamodeld文件)發生更改並且尚未清除現有數據時,會發生此問題。 您最終得到一個與舊模型下生成的數據相關聯的新模型,並且您嘗試在設備之間同步該混合...
將來,要避免與模型相關的問題,請查看核心數據模型版本控制和數據遷移。 https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/CoreDataVersioning/Articles/Introduction.html
希望它能解決你的問題。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.