0

iCloudをバックエンドとして使用してEnsemblesフレームワークを統合しようとしているコアデータアプリケーションがあります。あるデバイスで変更を行う場合、リモートの変更を取得するには、変更を加えて他のデバイスにコンテキストを保存する必要があることを除いて、ほとんどのことが機能しています。

データを反映するテーブルビューは に準拠していNSFetchedResultsControllerDelegateます。ローカル データが変更され、リモートの変更が取得されると、リモートの変更が正しく反映されます。

手動で呼び出す「同期」ボタンsyncWithCompletion(下記) を実装すると、変更が反映されません。

を呼び出して 2 分ごとに起動するタイマーはsyncWithCompletion、変更を取得しません。

同期をオフにしてから再度オンにすると、変更が反映されます。

アプリを再起動しても変更は反映されません。

#pragma mark - ENSEMBLES

- (void)setupEnsembles {
  if (ensemblesDataDebug==1) { printf("Running %s\n", [NSStringFromSelector(_cmd) UTF8String]); }

  // set the sync UI on
  [[NSNotificationCenter defaultCenter] postNotificationName:@"setSyncUIOn" object:nil];

  // setup ensemble
  self.cloudFileSystem = [[CDEICloudFileSystem alloc] initWithUbiquityContainerIdentifier:nil];
  self.ensemble = [[CDEPersistentStoreEnsemble alloc] initWithEnsembleIdentifier:@"RecordStore"
                                                              persistentStoreURL:self.storeURL
                                                           managedObjectModelURL:[self modelURL]
                                                                 cloudFileSystem:self.cloudFileSystem];
  self.ensemble.delegate = self;

  // Listen for local saves, and trigger merges
  [[NSNotificationCenter defaultCenter] addObserver:self
                                           selector:@selector(localSaveOccurred:)
                                               name:CDEMonitoredManagedObjectContextDidSaveNotification
                                             object:nil];

  [[NSNotificationCenter defaultCenter] addObserver:self
                                           selector:@selector(cloudDataDidDownload:)
                                               name:CDEICloudFileSystemDidDownloadFilesNotification
                                             object:nil];

  [self syncWithCompletion:NULL];

  // configure a timer to trigger a merge every two minutes
  if (!self.ensemblesSyncTimer) {
    self.ensemblesSyncTimer = [NSTimer scheduledTimerWithTimeInterval:120.0
                                                               target:self
                                                             selector:@selector(performScheduledSync:)
                                                             userInfo:nil
                                                              repeats:YES];
  }
}

- (void)performScheduledSync:(NSTimer*)aTimer {
  if (ensemblesDataDebug==1) { printf("Running %s\n", [NSStringFromSelector(_cmd) UTF8String]); }
  [self syncWithCompletion:NULL];
}

- (void)syncWithCompletion:(void(^)(void))completion {
  if (ensemblesDataDebug==1) { printf("Running %s\n", [NSStringFromSelector(_cmd) UTF8String]); }

  // set the sync UI on
  [[NSNotificationCenter defaultCenter] postNotificationName:@"setSyncUIOn" object:nil];

  // this checks to make sure there is an ensemble, because this method
  // can be called without knowing whether ensembles is enabled or not
  if (self.ensemble) {
    if (coreDataDebug==1) { NSLog(@"there is an ensemble, going to leech or merge"); }

    if (!self.ensemble.isLeeched) {
      if (coreDataDebug==1) { NSLog(@"leeching"); }
      [self.ensemble leechPersistentStoreWithCompletion:^(NSError *error) {
        if (error) NSLog(@"Error in leech: %@", [error localizedDescription]);

        // set the last synced date
        NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
        dateFormatter.timeStyle = NSDateFormatterMediumStyle;
        dateFormatter.dateStyle = NSDateFormatterMediumStyle;
        [dateFormatter setLocale:[NSLocale currentLocale]];
        [[NSUserDefaults standardUserDefaults] setObject:[dateFormatter stringFromDate:[NSDate date]]
                                                  forKey:@"iCloudLastSyncDate"];

        [[NSNotificationCenter defaultCenter] postNotificationName:@"setSyncUIOff" object:nil];
                                                            object:nil];
        if (completion) {completion();}
      }];
    }
    else {
      if (coreDataDebug==1) { NSLog(@"merging"); }
      [self.ensemble mergeWithCompletion:^(NSError *error) {
        if (error) NSLog(@"Error in merge: %@", [error localizedDescription]);

        // set the last synced date
        NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
        dateFormatter.timeStyle = NSDateFormatterMediumStyle;
        dateFormatter.dateStyle = NSDateFormatterMediumStyle;
        [dateFormatter setLocale:[NSLocale currentLocale]];
        [[NSUserDefaults standardUserDefaults] setObject:[dateFormatter stringFromDate:[NSDate date]]
                                                  forKey:@"iCloudLastSyncDate"];

        [[NSNotificationCenter defaultCenter] postNotificationName:@"setSyncUIOff" object:nil];
        [[NSNotificationCenter defaultCenter] postNotificationName:@"recordCollectionNeedsRefresh"
                                                            object:nil];
        if (completion) {completion();}
      }];
    }
  }
}

- (void)localSaveOccurred:(NSNotification *)notif {
  if (ensemblesDataDebug==1) { printf("Running %s\n", [NSStringFromSelector(_cmd) UTF8String]); }
  [self syncWithCompletion:NULL];
}

- (void)cloudDataDidDownload:(NSNotification *)notif {
  if (ensemblesDataDebug==1) { printf("Running %s\n", [NSStringFromSelector(_cmd) UTF8String]); }
  [self syncWithCompletion:NULL];
}

- (void)persistentStoreEnsemble:(CDEPersistentStoreEnsemble *)ensemble didSaveMergeChangesWithNotification:(NSNotification *)notification {
  if (ensemblesDataDebug==1) { printf("Running %s\n", [NSStringFromSelector(_cmd) UTF8String]); }

  [_context performBlockAndWait:^{
    [_context mergeChangesFromContextDidSaveNotification:notification];
  }];
}

- (NSArray *)persistentStoreEnsemble:(CDEPersistentStoreEnsemble *)ensemble globalIdentifiersForManagedObjects:(NSArray *)objects {
  if (ensemblesDataDebug==1) { printf("Running %s\n", [NSStringFromSelector(_cmd) UTF8String]); }
  return [objects valueForKeyPath:@"uniqueIdentifier"];
}

- (void)removeEnsembles {
  if (ensemblesDataDebug==1) { printf("Running %s\n", [NSStringFromSelector(_cmd) UTF8String]); }
  [self disconnectFromSyncServiceWithCompletion:NULL];
}

- (void)disconnectFromSyncServiceWithCompletion:(CDECodeBlock)completion {
  if (ensemblesDataDebug==1) { printf("Running %s\n", [NSStringFromSelector(_cmd) UTF8String]); }
  [self.ensemble deleechPersistentStoreWithCompletion:^(NSError *error) {

    self.ensemble.delegate = nil;
    [self.ensemble dismantle];
    self.ensemble = nil;
    [[NSUserDefaults standardUserDefaults] removeObjectForKey:@"iCloudLastSyncDate"];
    [[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"iCloudSyncingEnabled"];
    [self.ensemblesSyncTimer invalidate];
    self.ensemblesSyncTimer = nil;

  if (completion) completion();
  }];
}

- (void)persistentStoreEnsemble:(CDEPersistentStoreEnsemble *)ensemble didDeleechWithError:(NSError *)error {
  if (ensemblesDataDebug==1) { printf("Running %s\n", [NSStringFromSelector(_cmd) UTF8String]); }
  NSLog(@"Store did deleech with error: %@", error);
}

私が間違っているアイデアはありますか?

[コメントが長すぎるので編集]

まず、ローカルに保存してクラウドに変更がある場合は呼び出されdidSaveMergeChangesWithNotificationませ(変更が反映されていると仮定します-知る方法はありますか?それを除外するためにかなり長い間待ちました)。手動同期をトリガーすると呼び出されます。これは、ローカル モデルに変更を加えてコンテキストを保存したときにのみ呼び出されます。それが私をどこに残すのか、私にはよくわかりません。次に、フェッチ コントローラーを確認すると、クラウド内の変更は実際にはプルダウンされていません。私はCDELoggingLevelVerbose調査を続けることにしましたが、私が根本的に間違っていることを知っています。

また、これは非常に大きな変更です。Ensembles Github の古い問題から、シミュレーターで iCloud 同期をトリガーすると実際に機能することに気付きました! 残念ながら、私はデバイスを持っていないので、すべてのテストをシミュレーターで行っています (テスト中にあまりにも多くの iCloud ログインで iPhone を焼き尽くしました)。これでしょうか?これが実際に正常に動作していると確信できますが、シミュレーターに実際に iCloud 同期をトリガーさせない何かがありますか?

4

1 に答える 1

1

うまくいかない理由はよくわかりませんが、調べてみることができることがいくつかあります。

まず、(同期ボタンを押して) 単なるマージではなく、ローカルに保存した場合の違いをログから把握してみてください。didSaveMergeChangesWithNotification:デリゲート メソッドは両方の場合にトリガーされますか? クラウドに変更があると仮定すると、変更する必要があります。

フェッチ結果コントローラーもチェックする価値があります。変更がストアに入る可能性はありますが、フェッチ コントローラーはそれらを取得しません。performFetch確認する 1 つの方法は、各マージの最後に UIを呼び出してリロードし、それが問題であるかどうかをテストすることです。

Ensembles が実際にデータを取得してマージしているかどうかを確認する別の方法は、詳細ログをオンにすることです。関数を使用してCDESetCurrentLogLevel、 を渡しCDELoggingLevelVerboseます。これにより、フレームワークが何をしているかに関する多くの情報が出力され、手がかりが得られるはずです。

于 2017-12-18T07:27:15.243 に答える