2011-11-16 16 views
6

コアデータを使用するiPhoneアプリとMacアプリを使用しています。Mac/iPhoneアプリ - コアデータをiCloud&デバイスと同期する(コアデータを使用)

私は、これらの2つのアプリケーションがiCloudストレージ経由でデータベースを同期させたいと考えています。

私はの実装に調整を行ったmergeiCloudChangesを追加managedObjectContext & persistentStoreCoordinator & - 更新レシピのコード例から:私はファイルが私の「/ユーザ/ ME /ライブラリ/モバイルに表示され見ることができます

#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をビルド/実行するときに "Documents"ディレクトリに移動します。
しかし、iCloudストレージと同期しているかどうかはわかりません。明らかに、iPhoneとMacの間のデータは同期されていません。
データをクラウドに移行するために実装する必要がある他の方法はありますか?
iCloudストレージに実際に入っているドキュメントを確認する方法はありますか?

答えて

3

これは簡単な部分解答です。あなたはiCloud上に保存されているかを見ることができます

Macの場合:

システムPreferences.app - >のiCloud - > '管理...' をクリックします。その後、すべてのリストが表示されますMac OS XまたはiOSに保存されたドキュメントを持つアプリ。 iOSの上で

設定 - >のiCloud - >アーカイブ&バックアップ - スペース以下>オプションは、その後のMac OS XまたはiOSに保存されたドキュメントを持っているすべてのアプリケーションのリストが表示されますを使用しました。

NSFileManagersetUbiquitous: itemAtURL: destinationURL: error:を使用している限り、ドキュメントはiCloudに送信され、他のデバイスに表示されるはずです。

+0

こんにちはマイク、ご返信ありがとうございます。 iCloudストレージをsys prefsでチェックしました。何もコピーされていないようです。よく見続ける。 その他のヒント? はまた、はい、私は実際に私が使用していない無NSFileManagerのsetUbiquitous – adamteale

+0

ああを使用していないのです「setUbiquitous:itemAtURL:destinationURL:エラー:」 - i「はaddPersistentStoreWithType」を使用して、それにNSPersistentStoreUbiquitousContentNameKey 含まれているオプションの辞書を渡していますこれは同じ考えです? 私は読んだことがあるだろう...私は私のアプリは、このラインでハングことに気づいた再び – adamteale

+0

ありがとう: '場合([[NSFileManager defaultManager] setUbiquitous:makeUbiquitous itemAtURL:fileURL destinationURL:destURLエラー:&ERR]){' 私はXcodeからアプリケーションを停止し、コンソールアプリケーションに表示されます: 'librariand:クライアントの接続は無効です:接続が無効です ' アイデアはありますか? – adamteale

1

もう1つの部分的な答え。あなたがまだいない場合は、http://www.raywenderlich.com/6015/beginning-icloud-in-ios-5-tutorial-part-1を見てください。私はあなたと同じこと、つまりMac AppとiOS アプリ共有データで作業しています。がんばろう。マーク

私はちょうどについて学んだ:http://mentalfaculty.tumblr.com/archive "アンダーザシート" CoreDataとiCloudを探します。見てみな!

0

私のコードは少し違って見えますが、別のクラスですべてのプロジェクトでそれを再利用しています。このような私のセットアップ私のNSPersistentStoreCoordinator:私はあなたのセットアップNSPersistentStoreUbiquitousContentNameKey欠場

// ---- iCloud Setup 

// fist container in entitlements 
NSURL *iCloudDirectoryURL = [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:nil]; 

// if iCloud is enabled setup the store 
if (iCloudDirectoryURL) { 

    __iCloudEnabled = true; 

    NSLog(@"iCloud:%@", [iCloudDirectoryURL absoluteString]); 
    // AppDelegate has to provide the contentnamekey 
    NSString *contentNameKey = [appDelegate dataStoreContentNameKey]; 

    options = [NSDictionary dictionaryWithObjectsAndKeys:contentNameKey, NSPersistentStoreUbiquitousContentNameKey, iCloudDirectoryURL, NSPersistentStoreUbiquitousContentURLKey, nil]; 
} 

:iCloudには(nilでない返すゼロURLForUbiquityContainerIdentifier)が有効になっているにもかかわらず場合。

2番目は明らかです。これはデバイスでのみ動作し、アプリIDにはiCloudが有効になっている必要があります。

関連する問題