1

コア データを iCloud と同期するために、次のコードを用意しました。ただし、私が言うときだけ同期させたいです。たとえば、wifi を使用している場合にのみ同期します。私はこれを行うことができますか?これが私のコードです:

- (NSManagedObjectContext *)managedObjectContext {

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

    NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];

    if (coordinator != nil) {
        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;

        managedObjectContext.mergePolicy = [[NSMergePolicy alloc]
                                            initWithMergeType:NSMergeByPropertyObjectTrumpMergePolicyType];
    }

    return managedObjectContext;
}

- (void)mergeChangesFrom_iCloud:(NSNotification *)notification {

    NSLog(@"Merging in changes from iCloud...");

    NSManagedObjectContext* moc = [self managedObjectContext];

    [moc performBlock:^{

        [moc mergeChangesFromContextDidSaveNotification:notification];

        NSNotification* refreshNotification = [NSNotification notificationWithName:@"SomethingChanged"
                                                                            object:self
                                                                          userInfo:[notification userInfo]];

        [[NSNotificationCenter defaultCenter] postNotification:refreshNotification];
    }];
}
- (NSManagedObjectModel *)managedObjectModel {

    if (managedObjectModel != nil) {
        return managedObjectModel;
    }
    NSString *modelPath = [[NSBundle mainBundle] pathForResource:@"EntryDatabase" ofType:@"momd"];
    NSURL *modelURL = [NSURL fileURLWithPath:modelPath];
    managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];

    return managedObjectModel;
}

- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {

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

    persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel: [self managedObjectModel]];
    NSPersistentStoreCoordinator *psc = persistentStoreCoordinator;

    // Set up iCloud in another thread:

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

        // ** Note: if you adapt this code for your own use, you MUST change this variable:
        NSString *iCloudEnabledAppID = @"iCloud ID is here, i removed it from stack overflow";

        // ** Note: if you adapt this code for your own use, you should change this variable:
        NSString *dataFileName = @"CoreDataStore.sqlite";

        // ** Note: For basic usage you shouldn't need to change anything else

        NSString *iCloudDataDirectoryName = @"Data.nosync";
        NSString *iCloudLogsDirectoryName = @"Logs";
        NSFileManager *fileManager = [NSFileManager defaultManager];

        NSString *storePath = [[self applicationDocumentsDirectory] stringByAppendingPathComponent:dataFileName];

        NSURL *localStore = [NSURL fileURLWithPath:storePath];

        NSURL *iCloud = [fileManager URLForUbiquityContainerIdentifier:nil];

        if (iCloud) {

            NSLog(@"iCloud is working");

            NSURL *iCloudLogsPath = [NSURL fileURLWithPath:[[iCloud path] stringByAppendingPathComponent:iCloudLogsDirectoryName]];

            NSLog(@"iCloudEnabledAppID = %@",iCloudEnabledAppID);
            NSLog(@"dataFileName = %@", dataFileName);
            NSLog(@"iCloudDataDirectoryName = %@", iCloudDataDirectoryName);
            NSLog(@"iCloudLogsDirectoryName = %@", iCloudLogsDirectoryName);
            NSLog(@"iCloud = %@", iCloud);
            NSLog(@"iCloudLogsPath = %@", iCloudLogsPath);

            if([fileManager fileExistsAtPath:[[iCloud path] stringByAppendingPathComponent:iCloudDataDirectoryName]] == NO) {
                NSError *fileSystemError;
                [fileManager createDirectoryAtPath:[[iCloud path] stringByAppendingPathComponent:iCloudDataDirectoryName]
                       withIntermediateDirectories:YES
                                        attributes:nil
                                             error:&fileSystemError];
                if(fileSystemError != nil) {
                    NSLog(@"Error creating database directory %@", fileSystemError);
                }
            }

            NSString *iCloudData = [[[iCloud path]
                                     stringByAppendingPathComponent:iCloudDataDirectoryName]
                                    stringByAppendingPathComponent:dataFileName];

            NSLog(@"iCloudData = %@", iCloudData);

            NSMutableDictionary *options = [NSMutableDictionary dictionary];
            [options setObject:[NSNumber numberWithBool:YES] forKey:NSMigratePersistentStoresAutomaticallyOption];
            [options setObject:[NSNumber numberWithBool:YES] forKey:NSInferMappingModelAutomaticallyOption];
            [options setObject:iCloudEnabledAppID            forKey:NSPersistentStoreUbiquitousContentNameKey];
            [options setObject:iCloudLogsPath                forKey:NSPersistentStoreUbiquitousContentURLKey];

            [psc lock];

            [psc addPersistentStoreWithType:NSSQLiteStoreType
                              configuration:nil
                                        URL:[NSURL fileURLWithPath:iCloudData]
                                    options:options
                                      error:nil];

            [psc unlock];
        }
        else {
            NSLog(@"iCloud is NOT working - using a local store");
            NSMutableDictionary *options = [NSMutableDictionary dictionary];
            [options setObject:[NSNumber numberWithBool:YES] forKey:NSMigratePersistentStoresAutomaticallyOption];
            [options setObject:[NSNumber numberWithBool:YES] forKey:NSInferMappingModelAutomaticallyOption];

            [psc lock];

            [psc addPersistentStoreWithType:NSSQLiteStoreType
                              configuration:nil
                                        URL:localStore
                                    options:options
                                      error:nil];
            [psc unlock];

        }

        dispatch_async(dispatch_get_main_queue(), ^{
            [[NSNotificationCenter defaultCenter] postNotificationName:@"SomethingChanged" object:self userInfo:nil];
        });
    });

    return persistentStoreCoordinator;

 }
4

1 に答える 1

2

私が知る限り、これは起こり得ません。とにかく、単純で効率的な方法ではありません。

http://developer.apple.com/library/mac/#documentation/General/Conceptual/iCloudDesignGuide/Chapters/iCloudFundametals.html

問題は、iCloud の操作が透過的でないことです。したがって、iOS は、同期がいつ、どのくらいの頻度で行われるかを決定します。上記のドキュメントで、Apple は「ベスト プラクティス」はサンドボックスまたは iCloud のみを使用することであると述べていますが、それらの間でデータをコピーしないでください。

そうは言っても、アップルはiCloudが利用できなくなったときの動作について言及しています. これは、あなたが提案しているシナリオに合っているようです。基本的に、通常どおりに設定し、必要なデータがあることを確認してから、iCloud を無効にし、データをサンドボックスに移動して作業する必要があります。同期したいときは、データをコピーして戻すだけです。

iCloud の可用性の変更を処理するには、NSUbiquityIdentityDidChangeNotification 通知の受信時に呼び出されるメソッドを実装します。メソッドは次の作業を実行する必要があります。

ubiquityIdentityToken メソッドを呼び出し、その戻り値を格納します。新しい値を以前の値と比較して、ユーザーが自分のアカウントからサインアウトしたか、別のアカウントにサインインしたかを確認します。以前使用していたアカウントが使用できなくなった場合は、必要に応じて現在の状態をローカルに保存し、iCloud 関連のデータ キャッシュを空にして、iCloud 関連のすべてのユーザー インターフェイス要素を更新します。iCloud を利用できない状態でユーザーが引き続きコンテンツを作成できるようにする場合は、そのコンテンツをアプリのサンドボックス コンテナーに保存します。アカウントが再び使用可能になったら、新しいコンテンツを iCloud に移動します。通常は、ユーザーに通知したり、ユーザーの操作を要求したりせずにこれを行うのが最善です。

これはあなたの要件に合っているようです。しかし、私自身もまだこの段階に来ているので、これ以上コメントすることはできません。

于 2013-04-08T11:42:25.030 に答える