在核心数据存储之间切换

时间:2012-10-03 01:00:01

标签: ios cocoa core-data magicalrecord

我目前正在更新应用以使用Core Data。您可以说的应用程序是“数据库查看器”,一次只能查看一个数据库。每个数据库都保存在自己的单独文件夹中。目前,数据被下载并存储为一组plist文件。

在新版本中,我需要将这些plist数据库转换为Core Data存储(每个数据库一个存储。)我已经设置了创建单独存储文件的方法,并创建了实体。问题是所有实体都保存到我创建的第一个数据库中,而不是保存到“当前”或“最后创建”的文件中。

我正在使用的基本流程是:

//For each database {
//Create the sqlite file and set up NSManagedObjectContext
[MagicalRecord setupCoreDataStackWithStoreNamed:
    [NSURL fileURLWithPath:
    [NSString stringWithFormat:@"%@/%@/%@.sqlite",
    dirPath, directory, directory]]];
NSManagedObjectContext *managedObjectContext = 
    [NSManagedObjectContext MR_contextForCurrentThread];

//Iterate through all the plist files and create the necessary entities.
//Save new entities to file
[managedObjectContext MR_save];
//Clean up all cashes
[MagicalRecord cleanUp];
}

如何在商店之间正确切换,基本上“重置”每个交换机之间的所有内容。最好(如果可能的话)使用魔法记录。

编辑: 我发现了问题的一部分,并删除了大部分不需要的行为。事实证明,您无法在后台线程上可靠地调用[MagicalRecord cleanUp]。此外,它没有做我认为应该做的事情(见下文)。我在每次“保存”之后最终回调主线程以重置Core Data堆栈。这样做会为前三个数据库创建一个新的上下文。之后,它从三个数据库之前的数据库复制上下文。因此在循环中使用相同的三个上下文。

这就是我现在拥有的; 我通过创建后台线程并运行代码来在后台创建单个数据库来启动该过程:

backgroundQueue = dispatch_queue_create("com.BrandonMcQuilkin.myQueue", NULL);
    dispatch_async(backgroundQueue, ^(void) {
        [self createSQLiteDatabase:updateList];
    });

然后创建堆栈和数据库:

- (void)createSQLiteDatabase:(NSArray *)updateList
{
    NSString *directory = [updateList objectAtIndex:0];
    [MagicalRecord setupCoreDataStackWithStoreNamed:
        [NSURL fileURLWithPath:[NSString stringWithFormat:@"%@/%@/%@.sqlite",
        dirPath, directory, directory]]];
    NSManagedObjectContext *managedObjectContext = 
        [NSManagedObjectContext MR_contextForCurrentThread];
    //Check to see if the stack has reset
    NSLog(@"Before:%i", [[Competition MR_findAllInContext:managedObjectContext] count]);

    //Create and add entities to context...

    //Prepare for next loop
    NSLog(@"After:%i", [[Competition MR_findAllInContext:managedObjectContext] count]);
    [managedObjectContext MR_saveNestedContexts];
    [NSManagedObjectContext MR_resetContextForCurrentThread];

    NSMutableArray *temp = [[NSMutableArray alloc] initWithArray:updateList];
    [temp removeObjectAtIndex:0];

    dispatch_async(dispatch_get_main_queue(), ^(void){
        [self shouldContinueUpdating:temp];
    });

然后重置所有数据库并重复所有数据库:

- (void)shouldContinueUpdating:(NSArray *)databases
{
    //preform cleanup on main thread and release background thread
    [MagicalRecord cleanUp];
    dispatch_release(backgroundQueue);

    if ([databases count] != 0) {
        backgroundQueue = dispatch_queue_create("com.BrandonMcQuilkin.myQueue", NULL);
        dispatch_async(backgroundQueue, ^(void) {
            [self createSQLiteDatabase:databases];
        });
    }
}

使用两个NSLog,我在控制台中得到这个:(使用六个数据库,无论我转换多少个数据库,模式都是相同的。)

//First Loop
Before:0
After:308
//Second Loop
Before:0
After:257
//Third Loop
Before:0
After:37
//Fourth Loop
Before:308 
After:541 
//Fifth Loop
Before:257
After:490
//Sixth Loop
Before:37
After:270
... Keep adding to each of the three contexts.

[MagicalRecord cleanUp]并没有按照它所说的做。这是该方法应该做的。

+ (void) cleanUpStack;
{
[NSManagedObjectContext MR_cleanUp];
[NSManagedObjectModel MR_setDefaultManagedObjectModel:nil];
[NSPersistentStoreCoordinator MR_setDefaultStoreCoordinator:nil];
[NSPersistentStore MR_setDefaultPersistentStore:nil];
}

但事实证明,每次我保存时,NSStoreCoordinator都是同一个协调器,位于同一个内存位置,每个商店都在闲逛。有些东西不能正常工作......

2 个答案:

答案 0 :(得分:0)

MagicalRecord可能不适合这项工作......

首先,让我们更正你对setupCoreDataStackWithStoreNamed:方法的使用。该参数采用NSString,而不是URL,也不采用文件路径。 MagicalRecord将为您选择合适的路径并在那里创建您的商店。生成的sqlite文件很可能以您希望的路径命名。

接下来,您需要为此文件动态创建CoreData模型。这有点难,但可能。您需要遍历这些plist文件,并解释实体,属性和关系,并创建相应的NSEntityDescriptions,NSAttributeDescriptions和NSRelationshipDesctiptions并“手动”填充NSManagedObjectModel。你想要寻找方法

- [NSManagedObjectModel setEntities:(NSArray *)]

以及NSEntityDescription,NSAttributeDescription和NSRelationshipDescription的创建方法。

您还希望将此模型保存在某个位置,这样您就不必每次都重新创建它。幸运的是,它符合NSCoding,因此您应该只能将其保存到磁盘。

之后,您可能希望填充数据。从这里,MagicalRecord可以帮助您。我建议查看我为Importing Data Made Easy

撰写的Cocoa is My Girlfriend博文

如果您想“切换商店”,我想这意味着您要为每个plist文件创建一个新商店,那么您将不得不拆除每个文件的整个Core Data堆栈。如果您设法将MagicalRecord用于此项目,则需要查看[MagicalRecord cleanUp],然后重新开始。如果每个模型都相同,您可以通过发布持久性商店协调员,并为您的商店创建一个新的协调器。但由于你的“模式”可能会有所不同,你只需要抓住所有内容并重新开始。

答案 1 :(得分:0)

结果我遇到的问题是因为MagicalRecord中的错误。我在这里提交了一个git问题:https://github.com/magicalpanda/MagicalRecord/issues/270