为啥我的对象更新为 MagicalRecord 持久存储执行了两次?

Posted

技术标签:

【中文标题】为啥我的对象更新为 MagicalRecord 持久存储执行了两次?【英文标题】:Why is my object update executed twice for the MagicalRecord persistent store?为什么我的对象更新为 MagicalRecord 持久存储执行了两次? 【发布时间】:2014-02-04 08:23:07 【问题描述】:

我已将最新的 MagicalRecord 开发分支代码 (eb72053) 添加到带有核心数据的新 XCode 5.0.2 空项目中。

我为 Person 创建了以下简单模型:

然后,除了创建 NSManagedObject 子类 Person 并将 MagicalRecord 导入添加到我的 .pch 文件之外,我将我的应用程序委托设置为以下内容:

#import "MRFAppDelegate.h"
#import "Person.h"

@implementation MRFAppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions

    [self dataTests];
    return YES;


- (void)dataTests 
    [MagicalRecord setupCoreDataStackWithStoreNamed:@"MagicalRecordFunTests.sqlite"];

    Person *person = [Person findFirst];
    if (!person) 
        NSLog(@"Could not find person");
        person = [Person createEntity];
    

    NSLog(@"currentAge: %@", person.age);
    person.age = [NSNumber numberWithInteger:[person.age integerValue] + 10];
    NSLog(@"newAge: %@", person.age);

    person.name = [NSString stringWithFormat:@"%@, and now I am %@", person.name, person.age];

    [[NSManagedObjectContext defaultContext] saveToPersistentStoreAndWait];

    exit(0);


@end

现在,当我第一次运行它时,我会在控制台中看到以下预期输出:

2014-02-04 03:12:50.602 MagicalRecordFun[24299:70b] +[NSManagedObjectContext(MagicalRecord) MR_contextWithStoreCoordinator:](0x4ff0ac) -> Created Context UNNAMED
2014-02-04 03:12:50.604 MagicalRecordFun[24299:70b] +[NSManagedObjectContext(MagicalRecord) MR_setRootSavingContext:](0x4ff0ac) Set Root Saving Context: <NSManagedObjectContext: 0x8d1dc90>
2014-02-04 03:12:50.605 MagicalRecordFun[24299:70b] +[NSManagedObjectContext(MagicalRecord) MR_newMainQueueContext](0x4ff0ac) Created Main Queue Context: <NSManagedObjectContext: 0x8a0e290>
2014-02-04 03:12:50.605 MagicalRecordFun[24299:70b] +[NSManagedObjectContext(MagicalRecord) MR_setDefaultContext:](0x4ff0ac) Set Default Context: <NSManagedObjectContext: 0x8a0e290>
2014-02-04 03:12:50.608 MagicalRecordFun[24299:70b] Could not find person
2014-02-04 03:12:50.609 MagicalRecordFun[24299:70b] currentAge: 0
2014-02-04 03:12:50.610 MagicalRecordFun[24299:70b] newAge: 10
2014-02-04 03:12:50.610 MagicalRecordFun[24299:70b] -[NSManagedObjectContext(MagicalSaves) MR_saveWithOptions:completion:](0x8a0e290) → Saving <NSManagedObjectContext (0x8a0e290): *** DEFAULT ***> on *** MAIN THREAD ***
2014-02-04 03:12:50.611 MagicalRecordFun[24299:70b] -[NSManagedObjectContext(MagicalSaves) MR_saveWithOptions:completion:](0x8a0e290) → Save Parents? 1
2014-02-04 03:12:50.612 MagicalRecordFun[24299:70b] -[NSManagedObjectContext(MagicalSaves) MR_saveWithOptions:completion:](0x8a0e290) → Save Synchronously? 1
2014-02-04 03:12:50.612 MagicalRecordFun[24299:70b] -[NSManagedObjectContext(MagicalRecord) MR_contextWillSave:](0x8a0e290) Context DEFAULT is about to save. Obtaining permanent IDs for new 1 inserted objects
2014-02-04 03:12:50.614 MagicalRecordFun[24299:70b] -[NSManagedObjectContext(MagicalSaves) MR_saveWithOptions:completion:](0x8d1dc90) → Saving <NSManagedObjectContext (0x8d1dc90): *** BACKGROUND SAVING (ROOT) ***> on *** MAIN THREAD ***
2014-02-04 03:12:50.615 MagicalRecordFun[24299:70b] -[NSManagedObjectContext(MagicalSaves) MR_saveWithOptions:completion:](0x8d1dc90) → Save Parents? 1
2014-02-04 03:12:50.615 MagicalRecordFun[24299:70b] -[NSManagedObjectContext(MagicalSaves) MR_saveWithOptions:completion:](0x8d1dc90) → Save Synchronously? 1
2014-02-04 03:12:50.616 MagicalRecordFun[24299:70b] -[NSManagedObjectContext(MagicalRecord) MR_contextWillSave:](0x8d1dc90) Context BACKGROUND SAVING (ROOT) is about to save. Obtaining permanent IDs for new 1 inserted objects
2014-02-04 03:12:50.618 MagicalRecordFun[24299:70b] __70-[NSManagedObjectContext(MagicalSaves) MR_saveWithOptions:completion:]_block_invoke25(0x8d1dc90) → Finished saving: <NSManagedObjectContext (0x8d1dc90): *** BACKGROUND SAVING (ROOT) ***> on *** MAIN THREAD ***

但是,如果我打开新创建的 .sqlite 文件,我会看到意外数据,看起来我对模型所做的每次更新都被调用了两次:

sqlite> select ZAGE,ZNAME from ZPERSON;
20|(null), and now I am 10, and now I am 20

随后每次我运行该应用程序时,它都会执行相同的操作,从数据库中获取意外值,然后在模型对象的年龄上加 10,但在数据库中的年龄上加 20。

【问题讨论】:

我在使用 master (7f5142c, v2.2) 时也看到了相同的行为 【参考方案1】:

在我看来,您一遍又一遍地运行这个测试应用程序,它只是在您指定这行代码时连接名称:

person.name = [NSString stringWithFormat:@"%@, and now I am %@", person.name, person.age];

由于您的数据输出中只有一条记录(sqlite 数据中的一行),这对我来说似乎是正确的行为。

【讨论】:

正确的行为是每次运行连接一次。每次运行都会连接两次,就像每次运行时添加两次年龄一样。 第一个“名称”为 (null),您实际上得到了 3 个连接。 第一个 concat 是 (null)", and now I am 10",这是预期的,因为它是一个新创建的对象。第二个连接是(null), and now I am 10, and now I am 20,我不知道这是从哪里来的(调试器只在person.name = 行中断一次。 您是否正在运行一个测试项目,即一个经过单元测试的项目?如果是这样,您可能会运行此方法两次,一次在 applicationDidFinishLaunch 中,另一次在测试中 我没有运行生成的测试,但为了确定,我删除了生成的测试用例以及默认的测试目标。删除了应用程序,做了一个干净的构建,仍然是同样的问题。它是可重现的还是我的构建工具有问题?【参考方案2】:

正如@casademora 指出的那样,MagicalRecord 在这种情况下表现正确。这里的问题是exit(0),它导致ios 模拟器第二次调用application:didFinishLaunchingWithOptions

将此示例代码移动到 main.m 或将 exit(0) 更改为 exit(1) 会得到正确的行为。

【讨论】:

以上是关于为啥我的对象更新为 MagicalRecord 持久存储执行了两次?的主要内容,如果未能解决你的问题,请参考以下文章

iOS MagicalRecord 之谜。为啥在 truncateAll 后重新启动时我的数据会重新出现?

MagicalRecord 调用多个保存方法

MagicalRecord UIApplicationDidEnterBackground

我正在尝试 MagicalRecord,但为啥只有在添加新属性后才会删除数据?

保存和重新访问后对象字段仍然出错 (MagicalRecord)

使用 MagicalRecord 更新 CoreData 记录会创建一个额外的空记录