iOS 11+如何将现有的核心数据迁移到共享应用程序组以用于扩展? [英] iOS 11+ How to migrate existing Core Data to Shared App Group for use in extension?

查看:97
本文介绍了iOS 11+如何将现有的核心数据迁移到共享应用程序组以用于扩展?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当我使用核心数据模板创建iOS 11应用时,它会在AppDelete.m中自动生成以下代码。

When I created an iOS 11 app using the core data template, it auto generated the following code in AppDelete.m.

synthesize persistentContainer = _persistentContainer;

- (NSPersistentContainer *)persistentContainer {
    // The persistent container for the application. This implementation creates and returns a container, having loaded the store for the application to it.
    @synchronized (self) {
        if (_persistentContainer == nil) {
            _persistentContainer = [[NSPersistentContainer alloc] initWithName:@"My_History"];
            [_persistentContainer loadPersistentStoresWithCompletionHandler:^(NSPersistentStoreDescription *storeDescription, NSError *error) {
                if (error != nil) {
                    // Replace this implementation with code to handle the error appropriately.
                    // abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.

                    /*
                     Typical reasons for an error here include:
                     * The parent directory does not exist, cannot be created, or disallows writing.
                     * The persistent store is not accessible, due to permissions or data protection when the device is locked.
                     * The device is out of space.
                     * The store could not be migrated to the current model version.
                     Check the error message to determine what the actual problem was.
                    */
                    NSLog(@"Unresolved error %@, %@", error, error.userInfo);
                    abort();
                }
            }];
        }
    }

    return _persistentContainer;
}

- (void)saveContext {
NSManagedObjectContext *context = self.persistentContainer.viewContext;
NSError *error = nil;
if ([context hasChanges] && ![context save:&error]) {
    // Replace this implementation with code to handle the error appropriately.
    // abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
    NSLog(@"Unresolved error %@, %@", error, error.userInfo);
    abort();
}

我想添加Today和iMessage扩展名,以访问核心数据。从我的阅读中,我需要将这些数据(如果存在)迁移到共享应用程序容器中。我该怎么办?

I would like to add a Today and iMessage extension that accesses the history in the core data. From what I read, I need to migrate this data if it exists to a shared app container. How would I do that?

代码在目标C中。

我已经阅读了与此相关的其他问题但是所有这些似乎都在苹果改变核心数据的工作方式以使其变得更容易之前。正如您在我的代码中看到的那样,我从未指定数据存储的确切文件名是什么。我看到的每个示例都有类似 My_History.sqllite的内容。我什至不知道我的是不是sql lite数据库,它只是由该代码创建的。

I have read other questions involving this but all of them seem to be before Apple changed the way core data works to make it easier. As you can see in my code, I never specified what the data store exact file name is. Every example I saw had something like "My_History.sqllite". I don't even know if mine is a sql lite database, it was just created by that code.

推荐答案

我最终得到它做以下。 sqlite文件实际上是我的init加上最后一个.sqlite的名称。

I ended up getting it doing the following. The sqlite file was actually the name of my init plus .sqlite at the end.

+ (NSPersistentContainer*) GetPersistentContainer {
    //Init the store.
    NSPersistentContainer *_persistentContainer = [[NSPersistentContainer alloc] initWithName:@"Test_App"];

    //Define the store url that is located in the shared group.
    NSURL* storeURL = [[[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:@"group.Test_App"] URLByAppendingPathComponent:@"Test_App.sqlite"];

    //Determine if we already have a store saved in the default app location.
    BOOL hasDefaultAppLocation = [[NSFileManager defaultManager] fileExistsAtPath: _persistentContainer.persistentStoreDescriptions[0].URL.path];

    //Check if the store needs migration.
    BOOL storeNeedsMigration = hasDefaultAppLocation && ![_persistentContainer.persistentStoreDescriptions[0].URL.absoluteString isEqualToString:storeURL.absoluteString];

    //Check if the store in the default location does not exist.
    if (!hasDefaultAppLocation) {
        //Create a description to use for the app group store.
        NSPersistentStoreDescription *description = [[NSPersistentStoreDescription alloc] init];

        //set the automatic properties for the store.
        description.shouldMigrateStoreAutomatically = true;
        description.shouldInferMappingModelAutomatically = true;

        //Set the url for the store.
        description.URL = storeURL;

        //Replace the coordinator store description with this description.
        _persistentContainer.persistentStoreDescriptions = [NSArray arrayWithObjects:description, nil];
    }

    //Load the store.
    [_persistentContainer loadPersistentStoresWithCompletionHandler:^(NSPersistentStoreDescription *storeDescription, NSError *error) {
        //Check that we do not have an error.
        if (error == nil) {
            //Check if we need to migrate the store.
            if (storeNeedsMigration) {
                //Create errors to track migration and deleting errors.
                NSError *migrateError;
                NSError *deleteError;

                //Store the old location URL.
                NSURL *oldStoreURL = storeDescription.URL;

                //Get the store we want to migrate.
                NSPersistentStore *store = [_persistentContainer.persistentStoreCoordinator persistentStoreForURL: oldStoreURL];

                //Set the store options.
                NSDictionary *storeOptions = @{ NSSQLitePragmasOption : @{ @"journal_mode" : @"WAL" } };

                //Migrate the store.
                NSPersistentStore *newStore = [_persistentContainer.persistentStoreCoordinator migratePersistentStore: store toURL:storeURL options:storeOptions withType:NSSQLiteStoreType error:&migrateError];

                //Check that the store was migrated.
                if (newStore && !migrateError) {
                    //Remove the old SQLLite database.
                    [[[NSFileCoordinator alloc] init] coordinateWritingItemAtURL: oldStoreURL options: NSFileCoordinatorWritingForDeleting error: &deleteError byAccessor: ^(NSURL *urlForModifying) {
                        //Create a remove error.
                        NSError *removeError;

                        //Delete the file.
                        [[NSFileManager defaultManager] removeItemAtURL: urlForModifying error: &removeError];

                        //If there was an error. Output it.
                        if (removeError) {
                            NSLog(@"%@", [removeError localizedDescription]);
                        }
                    }
                     ];

                    //If there was an error. Output it.
                    if (deleteError) {
                        NSLog(@"%@", [deleteError localizedDescription]);
                    }
                }
            }
        } else {
            // Replace this implementation with code to handle the error appropriately.
            // abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.

            /*
             Typical reasons for an error here include:
             * The parent directory does not exist, cannot be created, or disallows writing.
             * The persistent store is not accessible, due to permissions or data protection when the device is locked.
             * The device is out of space.
             * The store could not be migrated to the current model version.
             Check the error message to determine what the actual problem was.
             */
            NSLog(@"Unresolved error %@, %@", error, error.userInfo);
            abort();
        }
    }];

    //Return the container.
    return _persistentContainer;
}

这篇关于iOS 11+如何将现有的核心数据迁移到共享应用程序组以用于扩展?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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