为啥我的对象更新为 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 UIApplicationDidEnterBackground
我正在尝试 MagicalRecord,但为啥只有在添加新属性后才会删除数据?