将核心数据与iCloud同步 – 不包括实体

我添加到一个现有的应用程序的iCloud。 同步正常工作,但是我需要排除一些实体,或由于我的一些核心数据被复制而提出解决办法。

例如:

CertificateColour发送到一个表视图,每一行现在显示两次。

CertificateType在操作表中提供了四个选项,现在有8行,每行重复一次。

即时通讯使用https://github.com/mluisbrown/iCloudCoreDataStack我的核心数据同步。

我检查了核心数据+ iCloud:从同步排除某些属性? 这表明了一些事情:
1.创build一个单独的本地和云存储,听起来…有前途,但不知道如何,因为这是我第一次尝试使用iCloud和Core数据。
2.第二个build议是同步到包含唯一设备标识符的实体,但是这已被弃用,并且不能确定核心数据的处理

AppDelegate.h

 #import <UIKit/UIKit.h> #import <sqlite3.h> #import "PersistentStack.h" @interface ICAppDelegate : UIResponder <UIApplicationDelegate> @property (strong, nonatomic) UIWindow *window; @property (strong, nonatomic) UINavigationController *navigationController; @property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext; @property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel; @property (readonly, strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator; - (void)saveContext; - (NSURL *)applicationDocumentsDirectory; @end 

Appdelegate.m

 @interface ICAppDelegate () <DBSessionDelegate, DBNetworkRequestDelegate> //iCloud @property (nonatomic, strong) PersistentStack* persistentStack; @property (nonatomic, strong) NSManagedObjectContext* managedObjectContext; @end @implementation ICAppDelegate @synthesize window = _window; @synthesize navigationController = _navigationController; @synthesize managedObjectContext = __managedObjectContext; @synthesize managedObjectModel = __managedObjectModel; @synthesize persistentStoreCoordinator = __persistentStoreCoordinator; - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { //iCloud self.persistentStack = [[PersistentStack alloc] initWithStoreURL:self.storeURL modelURL:self.modelURL]; self.managedObjectContext = self.persistentStack.managedObjectContext; BOOL populateData = NO; BOOL copyDb = YES; // Copy DB to documents directory if (copyDb == YES) { NSString *srcPath = [[NSBundle mainBundle] pathForResource:@"myApp" ofType:@"sqlite"]; NSString *destPath = [[NSHomeDirectory() stringByAppendingPathComponent:@"Documents"] stringByAppendingPathComponent:@"myApp.sqlite"]; if (![[NSFileManager defaultManager] fileExistsAtPath:srcPath]) { DebugLog(@"Source file doesn't exist"); } if (![[NSFileManager defaultManager] fileExistsAtPath:destPath]) { DebugLog(@"Copying DB to documents directory"); NSError *error = nil; [[NSFileManager defaultManager] copyItemAtPath:srcPath toPath:destPath error:&error]; if (error != nil) { DebugLog(@"Copy failed %@", [error localizedDescription]); } } } /////*****ALL OF THIS IS DUPLICATED AND NEEDS EXCLUDING FROM ICLOUD BACK UP****//////////// if (populateData) { DebugLog(@"Populating database"); NSManagedObjectContext *context = [self managedObjectContext]; Subscription *subscription = (Subscription *)[NSEntityDescription insertNewObjectForEntityForName:@"Subscription" inManagedObjectContext:context]; subscription.subscribed = @NO; CertificateColour *red = (CertificateColour *)[NSEntityDescription insertNewObjectForEntityForName:@"CertificateColour" inManagedObjectContext:context]; red.name = @"Red"; red.redComponent = @1.0f; red.greenComponent = @0.0f; red.blueComponent = @0.0f; CertificateColour *purple = (CertificateColour *)[NSEntityDescription insertNewObjectForEntityForName:@"CertificateColour" inManagedObjectContext:context]; purple.name = @"Purple"; purple.redComponent = @0.4f; purple.greenComponent = @0.0f; purple.blueComponent = @0.6f; CertificateColour *green = (CertificateColour *)[NSEntityDescription insertNewObjectForEntityForName:@"CertificateColour" inManagedObjectContext:context]; green.name = @"Green"; green.redComponent = @0.0f; green.greenComponent = @0.6f; green.blueComponent = @0.2f; CertificateColour *blue = (CertificateColour *)[NSEntityDescription insertNewObjectForEntityForName:@"CertificateColour" inManagedObjectContext:context]; blue.name = @"Blue"; blue.redComponent = @0.0f; blue.greenComponent = @0.2f; blue.blueComponent = @1.0f; ICCertificateTypeManager *ctm = [ICCertificateTypeManager manager]; CertificateType *type = [ctm newCertificateType]; type.title = @"Works"; type.identifier = @(Works); type = [ctm newCertificateType]; type.title = @"Type1"; type.identifier = @(Type1); type = [ctm newCertificateType]; type.title = @"Type2"; type.identifier = @(Type2); type = [ctm newCertificateType]; type.title = @"Type4"; type.identifier = @(Type3); [self saveContext]; } if ([[ICWebServiceClient sharedInstance] isLoggedIn]) { DebugLog(@"User is logged in "); } //////////////////////////////////////////////////////////// return YES; } - (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url { LogCmd(); if ([[DBSession sharedSession] handleOpenURL:url]) { if ([[DBSession sharedSession] isLinked]) { DebugLog(@"handling url"); } return YES; } return NO; } - (void)applicationWillResignActive:(UIApplication *)application { } - (void)applicationDidEnterBackground:(UIApplication *)application { [self.managedObjectContext save:NULL]; } - (void)applicationWillEnterForeground:(UIApplication *)application { } - (void)applicationDidBecomeActive:(UIApplication *)application { } - (void)applicationWillTerminate:(UIApplication *)application { [self saveContext]; } - (void)saveContext { NSError *error = nil; NSManagedObjectContext *managedObjectContext = self.managedObjectContext; if (managedObjectContext != nil) { if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error]) { NSLog(@"Unresolved error %@, %@", error, [error userInfo]); abort(); } } } #pragma mark - DBSessionDelegate - (void)sessionDidReceiveAuthorizationFailure:(DBSession*)session userId:(NSString *)userId { LogCmd(); } #pragma mark - DBNetworkRequestDelegate static int outstandingRequests; - (void)networkRequestStarted { outstandingRequests++; if (outstandingRequests == 1) { [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES]; } } - (void)networkRequestStopped { outstandingRequests--; if (outstandingRequests == 0) { [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO]; } } #pragma mark - Core Data stack // 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) { __managedObjectContext = [[NSManagedObjectContext alloc] init]; [__managedObjectContext setPersistentStoreCoordinator:coordinator]; } return __managedObjectContext; } // Returns the managed object model for the application. // If the model doesn't already exist, it is created from the application's model. - (NSManagedObjectModel *)managedObjectModel { if (__managedObjectModel != nil) { return __managedObjectModel; } NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"myApp" withExtension:@"momd"]; __managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL]; return __managedObjectModel; } // Returns the persistent store coordinator for the application. // If the coordinator doesn't already exist, it is created and the application's store added to it. - (NSPersistentStoreCoordinator *)persistentStoreCoordinator { if (__persistentStoreCoordinator != nil) { return __persistentStoreCoordinator; } NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"myApp.sqlite"]; NSError *error = nil; __persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]]; if (![__persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) { NSLog(@"Unresolved error %@, %@", error, [error userInfo]); abort(); } return __persistentStoreCoordinator; } #pragma mark - Application's Documents directory // Returns the URL to the application's Documents directory. - (NSURL *)applicationDocumentsDirectory { return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject]; } #pragma mark - iCloud store - (NSURL*)storeURL { NSURL* documentsDirectory = [[NSFileManager defaultManager] URLForDirectory:NSDocumentDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:YES error:NULL]; return [documentsDirectory URLByAppendingPathComponent:@"myApp.sqlite"]; } - (NSURL*)modelURL { return [[NSBundle mainBundle] URLForResource:@"myApp" withExtension:@"momd"]; } @end 

使用多个持久性存储实际上是从iCloud中排除特定实体types的唯一select。 您可以通过在同一个持久性存储协调器上多次调用addPersistentStoreWithType但使用不同的持久性存储文件(因为它可以在多个持久性存储之间进行协调而称为协调器)来执行此操作。 为其中一个商店使用iCloud选项,但不能用于其他商店。

您可以使用具有不同实体的两个单独的托pipe对象模型,也可以使用具有不同configuration选项的单个模型。 要么是有效的。

您可能会遇到的问题是您无法在不同的持久性存储文件中创build实例之间的关系 。 (从技术上说,你可以创build它们,但是你不能保存它们,在大多数情况下,它们是无用的)。 您的CertificateType实体听起来好像与其他实例有关系,但这不适用于多个商店。

你可以做的是同步每个对象,但添加代码来检测重复并处理它们。 在WWDC 2012的“使用iCloud与核心数据”会话的苹果的“SharedCoreData”示例应用程序中,有一个很好的例子,但我现在找不到该在线的副本。 你会做类似的事情

  1. 等待NSPersistentStoreDidImportUbiquitousContentChangesNotification
  2. 到达时,查看通知的userInfo ,看看是否包含任何CertificateType对象。
  3. 如果是这样,请为该实体提取查找并匹配重复项
  4. 以任何有意义的方式清理这些重复的内容。

更新:我忘了我已经做了一个博客文章,更详细地介绍了这一点 。 我还find了包含SharedCoreData的WWDC 2012示例代码包 (链接需要当前开发人员帐户)的链接。 该演示中的许多内容已经过时,但重复的删除代码与以前一样有效。