与iCloud同步核心数据 - 排除实体 [英] Syncing core data with iCloud - excluding entities

查看:149
本文介绍了与iCloud同步核心数据 - 排除实体的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

将iCloud添加到现有应用程序。同步工作正常,但我需要排除一些实体,或提出一个工作,因为我的一些核心数据被复制。

Im adding to iCloud to an existing app. Syncing works fine however I need to exclude some entities, or come up with a work around as some of my core data is being duplicated.

例如:

CertificateColour

CertificateType 在操作表中显示四个选项,现在是8行

CertificateType presents four options in a action sheet, now 8 rows are present, with each row having been duplicated once.

Im使用 https://github.com/mluisbrown/iCloudCoreDataStack 我的核心数据同步。

Im using https://github.com/mluisbrown/iCloudCoreDataStack for my core data sync.

我检出了核心数据+ iCloud:排除某些属性同步?这建议了几个事情:

1.创建一个单独的本地和云存储,听起来...承诺,但不知道如何这是我第一次尝试使用iCloud和Core数据。

2.第二个建议是同步到包含唯一设备标识符的实体,但这已被弃用,并再次不确定核心数据的进程

I checked out Core data + iCloud: exclude certain attributes from sync? That suggested a couple things:
1. Creating a separate local and cloud store, sounds...promising but not sure how as this is my first attempt with iCloud and Core data.
2. The second suggestion was sync to an entity that includes a unique device identifier but this is deprecated and again unsure of the process with core data

AppDelegate.h

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

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中排除特定实体类型的唯一选项。通过在同一持久存储协调器上多次调用 addPersistentStoreWithType ,但使用不同的持久存储文件(称为协调器,因为它可以在多个持久存储之间进行协调)。对于其中一个商店使用iCloud选项,而不使用其他商店。

Using multiple persistent stores is really the only option for excluding specific entity types from iCloud. You do that by calling addPersistentStoreWithType more than once on the same persistent store coordinator but with different persistent store files (it's called a coordinator because it can coordinate between multiple persistent stores). Use iCloud options for one of the stores but not for the other.

您可以使用具有不同实体的两个单独的受管对象模型,或者可以使用单个模型不同的配置选项。

You can either use two separate managed object models with different entities, or you can use a single model with different configuration options. Either is effective.

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

The problem you'll probably have with this is that you can't create relationships between instances in different persistent store files. (Technically you can create them, you just can't save them, which in most cases makes them useless). Your CertificateType entity sounds like it would have relationships to other instances, but that's not going to work with multiple stores.

你可以做的,而不是同步每个对象,但添加代码来检测重复和处理它们。在来自WWDC 2012上的使用iCloud with Core Data会话的Apple的SharedCoreData示例应用程序中有一个很好的例子,但我现在找不到在线的副本。您将执行

What you can do instead is sync every object but add code to detect the duplicates and deal with them. There was a good example of this in Apple's "SharedCoreData" sample app from the "Using iCloud with Core Data" session at WWDC 2012, but I can't find a copy of that online right now. You'd do something like


  1. 等待 NSPersistentStoreDidImportUbiquitousContentChangesNotification

  2. 到达时,查看通知的 userInfo ,看看是否包含任何 CertificateType 对象

  3. 如果是,请为该实体执行抓取以查找和匹配重复项。

  4. 清除这些重复项, 。

  1. Wait on NSPersistentStoreDidImportUbiquitousContentChangesNotification
  2. When it arrives, look at the notification's userInfo to see if any of your CertificateType objects are included.
  3. If so, do a fetch for that entity to find and match up duplicates
  4. Clean up those duplicates in whatever way makes sense for your app.

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

Update: I forgot that I had done a blog post which covers this in more detail. I also found a link to the WWDC 2012 sample code bundle (link requires current developer account) which includes SharedCoreData. A lot of what's in that demo is obsolete, but the duplicate removal code is as valid as ever.

这篇关于与iCloud同步核心数据 - 排除实体的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆