核心数据与集合同步:在本地模型更改之前,不会下拉远程更改

问题描述 投票:0回答:1

我有一个核心数据应用程序,我试图使用iCloud作为我的后端集成Ensembles框架。我有大部分工作,除了在一台设备上进行更改时,我必须进行更改并将上下文保存在另一台设备上,以便获取远程更改。

反映数据的tableview符合NSFetchedResultsControllerDelegate。当本地数据更改并且它接收远程更改时,远程更改会正确反映。

实现“同步”按钮,手动调用syncWithCompletion(下面)不会获取更改。

每隔两分钟发射一次的计时器,调用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同步实际上是有效的!不幸的是,我正在模拟器中进行所有测试,因为我没有任何设备(我在测试过程中烧了我的iPhone太多iCloud登录)。这可能吗?我是否可以确信这实际上是正常工作,但是模拟器中有些东西实际上并没有让iCloud同步触发器?

ios objective-c icloud ensembles
1个回答
1
投票

我不清楚为什么它不起作用,但有些事情你可以尝试找出。

首先,尝试从日志中找出当您进行本地保存而不仅仅是合并(通过按下同步按钮)时的不同之处。在两种情况下都会触发didSaveMergeChangesWithNotification:委托方法吗?假设云中有变化,它应该。

它也值得检查获取结果控制器。更改可能会进入存储,但获取控制器不会接收它们。一种检查方法是调用performFetch并在每次合并结束时重新加载UI,以测试是否可能出现问题。

另一种查看Ensembles是否实际获取和合并数据的方法是打开详细日志记录。使用函数CDESetCurrentLogLevel,并传入CDELoggingLevelVerbose。这将打印出有关框架正在做什么的大量信息,并应提供线索。

© www.soinside.com 2019 - 2024. All rights reserved.