Ios 核心数据与集成同步:远程更改不是';直到局部模型发生变化,才将其拉下
我有一个核心数据应用程序,我正试图使用iCloud作为我的后端来集成集成集成框架。除了在一台设备上进行更改时,我必须进行更改并将上下文保存在另一台设备上,以便它拾取远程更改之外,我的大部分工作都正常Ios 核心数据与集成同步:远程更改不是';直到局部模型发生变化,才将其拉下,ios,objective-c,icloud,ensembles,Ios,Objective C,Icloud,Ensembles,我有一个核心数据应用程序,我正试图使用iCloud作为我的后端来集成集成集成框架。除了在一台设备上进行更改时,我必须进行更改并将上下文保存在另一台设备上,以便它拾取远程更改之外,我的大部分工作都正常 #pragma mark - ENSEMBLES - (void)setupEnsembles { if (ensemblesDataDebug==1) { printf("Running %s\n", [NSStringFromSelector(_cmd) UTF8String]); }
#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);
}
反映数据的tableview符合NSFetchedResultsControllerDelegate
。当本地数据更改并拾取远程更改时,远程更改将正确反映
执行一个“Sync”按钮,手动调用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);
}
每两分钟触发一次的计时器,调用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);
}
关闭同步功能,然后再次打开同步功能,将拾取更改
#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);
}
重新启动应用程序不会拾取更改
#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
不会被调用,如果我进行了本地保存并且云中有更改(假设它们已经传播-有办法知道吗?我已经等了很长时间试图排除这种情况),也不会在触发手动同步时被调用。仅当我更改本地模型并保存上下文时,才会调用它。我不知道这会让我怎么样。其次,检查fetch控制器,云中的更改确实不会被拉下来。我已经打开了cdeloginglevelverbose
继续调查,但我知道我做了一些根本错误的事情,我一定是错过了
还有,这里有一个很大的变化——我刚刚从Ensembles Github中的一个老问题中认识到,在模拟器中触发iCloud同步实际上是可行的!不幸的是,我所有的测试都是在模拟器中进行的,因为我没有任何设备(在测试期间,我用过多的iCloud登录烧坏了我的iPhone)。可能是这个吗?我是否可以确信这确实正常工作,但模拟器中有一些东西实际上没有让iCloud同步触发?我不清楚为什么它不工作,但您可以尝试找出一些事情 首先,试着从日志中找出当您进行本地保存而不是仅仅进行合并时(通过按下同步按钮)有什么不同。在这两种情况下是否都会触发
didSaveMergeChangesWithNotification:
delegate方法?假设云中有变化,它应该会改变
还值得检查fetchresults控制器。有可能更改确实进入了存储区,但提取控制器没有将其提取出来。检查的一种方法是调用performFetch
,并在每次合并结束时重新加载UI,以测试这是否是问题所在
查看集成是否实际获取和合并数据的另一种方法是打开详细日志记录。使用函数
CDESetCurrentLogLevel
,并传入cdeloglinglevelverbose
。这将打印出大量关于框架正在做什么的信息,并提供线索。您是被可怕的“云对接”扩展击中了,还是制作了一个名为“ibutt”的定制后端?如果您只是使用iCloud Drive,一个可能的解释是同步文件需要一段时间。这是集成不能真正影响的,除了要求下载它们。@DrewMcCormack哈,对不起,是的,我确实安装了“云对接”。我编辑了这个问题,稍后我会在你的答案中尝试你的建议。通常我觉得这个扩展很有趣。今天不行。如果您在模拟器中进行测试,确实有可能没有正确下载文件。我听过用户在模拟器中遇到问题的报告。您可以尝试使用Xcode调试菜单触发iCloud文件同步。除了在设备上或Dropbox上进行测试之外,我只能推荐使用CloudKit的Ensembles2,但它是收费的。如果你能得到一个iPodtouch,也许测试就可以了。这似乎都是通过使用真实设备而不是模拟器来解决的。耸肩