ios - Mac/iPhone 应用程序 - 将核心数据同步到 iCloud 和设备(使用核心数据)

标签 ios macos core-data icloud nspersistentdocument

我正在开发一个使用 Core Data 的 iPhone 应用程序和一个 Mac 应用程序。

我想让这两个应用程序通过 iCloud 存储同步它们的数据库。

我对 managedObjectContextpersistentStoreCoordinator 的实现进行了调整,并添加了 mergeiCloudChanges - 来自更新的 Recipes 示例代码:

#pragma mark -
#pragma mark Core Data stack

// this takes the NSPersistentStoreDidImportUbiquitousContentChangesNotification
// and transforms the userInfo dictionary into something that
// -[NSManagedObjectContext mergeChangesFromContextDidSaveNotification:] can consume
// then it posts a custom notification to let detail views know they might want to refresh.
// The main list view doesn't need that custom notification because the NSFetchedResultsController is
// already listening directly to the NSManagedObjectContext
- (void)mergeiCloudChanges:(NSNotification*)note forContext:(NSManagedObjectContext*)moc {

    NSLog(@"merging iCloud stuff");

    [moc mergeChangesFromContextDidSaveNotification:note]; 

    NSNotification* refreshNotification = [NSNotification notificationWithName:@"RefreshAllViews" object:self  userInfo:[note userInfo]];

    [[NSNotificationCenter defaultCenter] postNotification:refreshNotification];
}

/**
 Returns the managed object context for the application.
 If the context doesn't already exist, it is created and bound to the persistent store coordinator for the application.
 */
- (NSManagedObjectContext *)managedObjectContext
{
    if (managedObjectContext != nil)
    {
        return managedObjectContext;
    }

    NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];

    if (coordinator != nil)
    {
        if (IOS_VERSION_GREATER_THAN_OR_EQUAL_TO(@"5.0")) {
            NSManagedObjectContext* moc = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];

            [moc performBlockAndWait:^{
                [moc setPersistentStoreCoordinator: coordinator];

                [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(mergeChangesFrom_iCloud:) name:NSPersistentStoreDidImportUbiquitousContentChangesNotification object:coordinator];
            }];
            managedObjectContext = moc;
        } else {
            managedObjectContext = [[NSManagedObjectContext alloc] init];
            [managedObjectContext setPersistentStoreCoordinator:coordinator];
        }

    }
    return managedObjectContext;
}

// NSNotifications are posted synchronously on the caller's thread
// make sure to vector this back to the thread we want, in this case
// the main thread for our views & controller
- (void)mergeChangesFrom_iCloud:(NSNotification *)notification {


     NSManagedObjectContext* moc = [self managedObjectContext];

    // this only works if you used NSMainQueueConcurrencyType
    // otherwise use a dispatch_async back to the main thread yourself
    [moc performBlock:^{
        [self mergeiCloudChanges:notification forContext:moc];
    }];
}


/**
 Returns the managed object model for the application.
 If the model doesn't already exist, it is created by merging all of the models found in the application bundle.
 */
- (NSManagedObjectModel *)managedObjectModel {

    if (managedObjectModel != nil) {
        return managedObjectModel;
    }
    managedObjectModel = [NSManagedObjectModel mergedModelFromBundles:nil];    
    return managedObjectModel;
}





- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {

    if (persistentStoreCoordinator__ != nil) {
        return persistentStoreCoordinator__;
    }

    // assign the PSC to our app delegate ivar before adding the persistent store in the background
    // this leverages a behavior in Core Data where you can create NSManagedObjectContext and fetch requests
    // even if the PSC has no stores.  Fetch requests return empty arrays until the persistent store is added
    // so it's possible to bring up the UI and then fill in the results later
    persistentStoreCoordinator__ = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel: [self managedObjectModel]];


    // prep the store path and bundle stuff here since NSBundle isn't totally thread safe
    NSPersistentStoreCoordinator* psc = persistentStoreCoordinator__;
     NSString *storePath = [[self applicationDocumentsDirectory] stringByAppendingPathComponent:@"MyApp.sqlite"];

    // do this asynchronously since if this is the first time this particular device is syncing with preexisting
    // iCloud content it may take a long long time to download
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSFileManager *fileManager = [NSFileManager defaultManager];

        NSURL *storeUrl = [NSURL fileURLWithPath:storePath];
        // this needs to match the entitlements and provisioning profile
        NSURL *cloudURL = [fileManager URLForUbiquityContainerIdentifier:nil];
        NSString* coreDataCloudContent = [[cloudURL path] stringByAppendingPathComponent:@"MyApp"];
        cloudURL = [NSURL fileURLWithPath:coreDataCloudContent];

        NSLog(@"cloudURL: %@", cloudURL);        

        //  The API to turn on Core Data iCloud support here.
        NSDictionary* options = [NSDictionary dictionaryWithObjectsAndKeys:@"xxxxxxxx.com.me.MyApp", 
                                 @"MyApp", 
                                 cloudURL, 
                                 NSPersistentStoreUbiquitousContentURLKey, 
                                 [NSNumber numberWithBool:YES], 
                                 NSMigratePersistentStoresAutomaticallyOption, 
                                 [NSNumber numberWithBool:YES], 
                                 NSInferMappingModelAutomaticallyOption,
                                 nil];

        NSError *error = nil;

        [psc lock];
        if (![psc addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeUrl options:options error:&error]) {
            /*
             Replace this implementation 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. If it is not possible to recover from the error, display an alert panel that instructs the user to quit the application by pressing the Home button.

             Typical reasons for an error here include:
             * The persistent store is not accessible
             * The schema for the persistent store is incompatible with current managed object model
             Check the error message to determine what the actual problem was.
             */
            NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
            abort();
        }    
        [psc unlock];

        // tell the UI on the main thread we finally added the store and then
        // post a custom notification to make your views do whatever they need to such as tell their
        // NSFetchedResultsController to -performFetch again now there is a real store
        dispatch_async(dispatch_get_main_queue(), ^{
            NSLog(@"asynchronously added persistent store!");
            [[NSNotificationCenter defaultCenter] postNotificationName:@"RefetchAllDatabaseData" object:self userInfo:nil];
        });
    });

    return persistentStoreCoordinator__;
}

当我构建/运行 myapp 时,我可以看到文件出现在我的“/Users/me/Library/Mobile Documents”目录中。
但我不知道它是否正在同步到 iCloud 存储 - 显然 iphone 和 mac 之间的数据没有同步。
我是否需要实现其他方法才能将数据移动到云端?
我有什么办法可以查看 iCloud 存储中实际有哪些文档?

最佳答案

这是一个快速的部分答案。

您可以看到存储在 iCloud 中的内容:

在苹果机上:

System Preferences.app -> iCloud -> 单击“管理...”,然后您将看到一个列表,其中包含所有存储有 Mac OS X 或 iOS 文档的应用程序。

在 iOS 上:

首选项 -> iCloud -> 存档和备份 -> 已用空间下方的选项 然后您将看到一个列表,其中列出了所有将文档存储在 Mac OS X 或 iOS 中的应用程序。

只要您使用 NSFileManagersetUbiquitous: itemAtURL: destinationURL: error:,文档就会为您发送到 iCloud 并显示在其他设备上.

关于ios - Mac/iPhone 应用程序 - 将核心数据同步到 iCloud 和设备(使用核心数据),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8154396/

相关文章:

ios - 如何将 UIImageView 设置为手机壁纸

ios - UITableView 不接触单个手势识别器

ios - Swift 中的选项和根 Controller 访问

macos - 全屏式 Mail.app 撰写 Pane

ios - 未保存的管理对象上下文对包含NONE或ANY的谓词产生异常

IOS如何制作 View 覆盖键盘

java - OSX 上 JAR 文件的推荐位置

python - 在 Mac 上安装 Scapy : "ImportError: No module named pcapy"

ios - 为什么app在设置属性时会陷入死循环?

iphone - 核心数据与 SQLite 持久对象