核心数据迁移问题

时间:2014-11-07 17:24:43

标签: ios sqlite core-data core-data-migration

我目前正在编写应用的下一个版本。

在旧版本中,没有CoreData sqlite

在新版本中,我们有一个本地CoreData sqlite数据库。

当我从头开始安装新版本的应用程序时,没有问题,商店就在那里,我可以查询。

但是,当我在具有上一版本的手机上安装应用程序时,我的查询会返回,但没有结果。

当我查看日志时,控制台中没有任何内容,并且不会返回任何错误。

   #import "CoreDataHelper.h"

@implementation CoreDataHelper
@synthesize store = _store;
@synthesize coordinator = _coordinator;


#pragma mark - 
#pragma mark - FILES
NSString *storeFileName = @"Reporting.sqlite";

#pragma mark - 
#pragma mark - PATHS
- (NSString *)applicationDocumentsDirectory {

    return [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];

}

- (NSURL *)applicationStoresDirectory {

    NSURL *storesDirectory = [[NSURL fileURLWithPath:[self applicationDocumentsDirectory]]URLByAppendingPathComponent:@"Stores"];

    NSFileManager *fileManager = [NSFileManager defaultManager];

    if (![fileManager fileExistsAtPath:[storesDirectory path]]) {
        NSError *error = nil;
        if ([fileManager createDirectoryAtURL:storesDirectory
                   withIntermediateDirectories:YES
                                    attributes:nil
                                         error:&error]) {
            //File created
        } else {

            //Error
        }
    }

    return storesDirectory;

}

- (NSURL *)storeURL {

    return [[self applicationStoresDirectory] URLByAppendingPathComponent:storeFileName];

}

#pragma mark - 
#pragma mark - SETUP
- (id)init {

    if (self = [super init]) {
        _model = [NSManagedObjectModel mergedModelFromBundles:nil];
        _coordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:_model];
        _context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
        [_context setPersistentStoreCoordinator:_coordinator];
    }

    return self;
}

- (void)loadStore {

    if (_store) return; // Don't load store if it is already loaded

    // to generate the database in the app launching comment next lines...

    if(![self getFileExistence:storeFileName]){
        // file URL in our bundle
        NSURL *fileFromBundle = [[NSBundle mainBundle]URLForResource:@"FaultReporting" withExtension:@"sqlite"];

        // Destination URL
        NSURL *destinationURL = [[self applicationStoresDirectory] URLByAppendingPathComponent:@"FaultReporting.sqlite"];

        // copy it over
        [[NSFileManager defaultManager]copyItemAtURL:fileFromBundle toURL:destinationURL error:nil];
    }

    // end of comments

    NSError *error = nil;

    @try {
        _store = [_coordinator addPersistentStoreWithType:NSSQLiteStoreType
                                            configuration:nil
                                                      URL:[self storeURL]
                                                  options:@{                                                         NSMigratePersistentStoresAutomaticallyOption: @(YES),
                                                            NSInferMappingModelAutomaticallyOption: @(YES)}
                                                    error:&error];
    }
    @catch (NSException *exception) {
        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Error" message:[NSString stringWithFormat:@"Error: %@, %@",error, [error userInfo]] delegate:self
                                              cancelButtonTitle:@"OK"
                                              otherButtonTitles:nil, nil];
        [alert show];
    }
    @finally {
        //
    }

}

3 个答案:

答案 0 :(得分:2)

苏。不确定你是否这样做但是尝试以下方法:

    NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
                             [NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
                             [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];
[[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:self.managedObjectModel];
    NSError* error;
    [managedObjectContext.persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType
                                                                  configuration:nil
                                                                            URL:self.storeUrl
                                                                        options:options // this is required to migrate some core data model attributes
                                                                          error:&error];

在您进行设置时,基本上必须告诉它在选项中使用此迁移功能。

答案 1 :(得分:1)

我不确定这是否适用于您,但从iOS 7升级到iOS 8时我遇到了类似的情况。在iOS 8 NSManagedObject中添加了deleted的属性。我碰巧在托管对象模型上有一个名为deleted的属性。我必须将已删除列的名称更改为与NSManagedObject上的新已删除属性不冲突的内容。

答案 2 :(得分:1)

您能否确认已执行了所有这些步骤?

第1步:添加框架

点击您的应用目标(在左侧窗格中显示带有应用名称的顶部图标),然后转到“构建阶段”标签,然后点击“链接二进制文件库”,点击“+”链接然后找到'CoreData.framework'并将其添加到您的项目

然后在所有需要它的对象上导入coredata:

#import <CoreData/CoreData.h>

或在.pch文件中的常用导入下添加导入:

#ifdef __OBJC__
    #import <UIKit/UIKit.h>
    #import <Foundation/Foundation.h>
    #import <CoreData/CoreData.h>
#endif

第2步:添加数据模型

要添加.xcdatamodel文件,请右键单击/按住Control键并单击右侧窗格中的文件(如在“资源”文件夹中保存),然后选择“添加新文件”,在选择文件类型时单击“核心数据”选项卡然后单击“数据模型”,为其命名并单击“下一步”和“完成”,它将把它添加到您的项目中。当您单击此Model对象时,您将看到使用您想要的任何关系将实体添加到项目的界面。


第3步:更新App Delegate

将这些对象添加到AppDelegate.h

 @property (nonatomic, retain, readonly) NSManagedObjectModel *managedObjectModel;
 @property (nonatomic, retain, readonly) NSManagedObjectContext *managedObjectContext;
 @property (nonatomic, retain, readonly) NSPersistentStoreCoordinator *persistentStoreCoordinator;

 - (NSURL *)applicationDocumentsDirectory; // nice to have to reference files for core data

在AppDelegate.m中合成以前的对象,如下所示:

@synthesize managedObjectContext = _managedObjectContext;
@synthesize managedObjectModel = _managedObjectModel;
@synthesize persistentStoreCoordinator = _persistentStoreCoordinator;

然后将这些方法添加到AppDelegate.m(确保将您添加的模型的名称放在显示的位置):

- (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();
        }
    }
}

- (NSManagedObjectContext *)managedObjectContext{
    if (_managedObjectContext != nil) {
        return _managedObjectContext;
    }

    NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
    if (coordinator != nil) {
        _managedObjectContext = [[NSManagedObjectContext alloc] init];
        [_managedObjectContext setPersistentStoreCoordinator:coordinator];
    }
    return _managedObjectContext;
}

- (NSManagedObjectModel *)managedObjectModel{
    if (_managedObjectModel != nil) {
        return _managedObjectModel;
    }
    NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"NAMEOFYOURMODELHERE" withExtension:@"momd"];
    _managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
    return _managedObjectModel;
}

- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
    if (_persistentStoreCoordinator != nil) {
        return _persistentStoreCoordinator;
    }

    NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"NAMEOFYOURMODELHERE.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];
}

步骤4:将数据对象获取到需要数据的ViewControllers

ViewController.h中的

@property (nonatomic, retain) NSManagedObjectContext *managedObjectContext;

在ViewController.m

@synthesize managedObjectContext = _managedObjectContext;

在AppDelegate或创建ViewController的类中,将managedObjectContext设置为与AppDelegate相同

ViewController.managedObjectContext = self.managedObjectContext;

如果您希望使用Core Data的viewcontroller成为FetchedResultsController,那么您需要确保这些内容在ViewController.h中

@interface ViewController : UIViewController <NSFetchedResultsControllerDelegate> {
  NSFetchedResultsController *fetchedResultsController;
  NSManagedObjectContext *managedObjectContext;
}

 @property (nonatomic, retain) NSFetchedResultsController *fetchedResultsController;

这是在ViewController.m

@synthesize fetchedResultsController, managedObjectContext;

参考: How to add Core Data to an existing project in Xcode

希望它能解决你的问题。