我正在将 iCloud 添加到现有应用程序。同步工作正常,但是我需要排除一些实体,或者在我的一些核心数据被复制时想出一个解决方法。
例如:
CertificateColour 被发送到表格 View ,现在每行显示两次。
CertificateType 在操作表中显示四个选项,现在有 8 行,每行都被复制一次。
我正在使用 https://github.com/mluisbrown/iCloudCoreDataStack用于我的核心数据同步。
我查看了 Core data + iCloud: exclude certain attributes from sync?这暗示了几件事:
1. 创建一个单独的本地和云存储,听起来……很有希望,但不确定这是我第一次尝试使用 iCloud 和 Core 数据。
2. 第二个建议是同步到包含唯一设备标识符的实体,但这已被弃用,并且再次不确定核心数据的流程
AppDelegate.h
#import <UIKit/UIKit.h>
#import <sqlite3.h>
#import "ersistentStack.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)applicationUIApplication *)application didFinishLaunchingWithOptionsNSDictionary *)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(@"opulating 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 = @"urple";
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)applicationUIApplication *)application handleOpenURLNSURL *)url {
LogCmd();
if ([[DBSession sharedSession] handleOpenURL:url]) {
if ([[DBSession sharedSession] isLinked]) {
DebugLog(@"handling url");
}
return YES;
}
return NO;
}
- (void)applicationWillResignActiveUIApplication *)application
{
}
- (void)applicationDidEnterBackgroundUIApplication *)application
{
[self.managedObjectContext save:NULL];
}
- (void)applicationWillEnterForegroundUIApplication *)application
{
}
- (void)applicationDidBecomeActiveUIApplication *)application
{
}
- (void)applicationWillTerminateUIApplication *)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)sessionDidReceiveAuthorizationFailureDBSession*)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
Best Answer-推荐答案 strong>
使用多个持久存储确实是从 iCloud 中排除特定实体类型的唯一选择。为此,您可以在同一个持久存储协调器上多次调用 addPersistentStoreWithType ,但使用不同的持久存储文件(它被称为协调器,因为它可以在多个持久存储之间进行协调)。对其中一个商店使用 iCloud 选项,但对另一个不使用。
您可以使用具有不同实体的两个单独的托管对象模型,也可以使用具有不同配置选项的单个模型。任何一个都有效。
您可能会遇到的问题是您无法在不同的持久存储文件中的实例之间创建关系。 (从技术上讲,您可以创建它们,但无法保存它们,这在大多数情况下使它们无用)。您的 CertificateType 实体听起来像是与其他实例有关系,但这不适用于多个商店。
您可以做的是同步每个对象,但添加代码以检测重复项并处理它们。在 WWDC 2012 的“将 iCloud 与核心数据一起使用” session 中,Apple 的“SharedCoreData”示例应用程序中有一个很好的例子,但我现在无法在网上找到该副本。你会做类似的事情
- 等待
NSPersistentStoreDidImportUbiquitousContentChangesNotification
- 收到通知后,查看通知的
userInfo 以查看是否包含任何 CertificateType 对象。
- 如果是这样,请对该实体进行提取以查找和匹配重复项
- 以任何对您的应用有意义的方式清理这些重复项。
更新:我忘了我做过 blog post which covers this in more detail .我还找到了 WWDC 2012 sample code bundle 的链接。 (链接需要当前的开发者帐户),其中包括 SharedCoreData。该演示中的很多内容都已过时,但重复删除代码与以往一样有效。
关于ios - 将核心数据与 iCloud 同步 - 不包括实体,我们在Stack Overflow上找到一个类似的问题:
https://stackoverflow.com/questions/22834654/
|