【问题标题】:Managed Object Context Save Doesn't Make It To Persistent Store托管对象上下文保存不能进入持久存储
【发布时间】:2011-08-16 13:41:36
【问题描述】:

在准备更新我的应用程序时,我发现了一个奇怪的问题,到目前为止,这有点让人头疼。

我有一个简单的方法,它获取一个托管对象,更新一个属性,然后将更改保存到持久存储。奇怪的是,在某些时候,它似乎并没有真正将堆栈一直保存到 DB,但它返回 true 以表示成功保存并且不填充 NSError 对象。

我已通过打开 SQL 日志记录验证了这一点 - 在一次调用中,我看不到 UPDATE 语句,但在第二次调用具有相同输入的相同方法时,我看到了 UPDATE。

真的很奇怪。我一定是做错了什么,但我一直盯着这个看了一天,我想不通。

这是有问题的方法:

+ (void)markTemplateAsPurchasedWithProductID:(NSString *)productID inContext:(NSManagedObjectContext *)context {    
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init]; 
NSEntityDescription *entity = [NSEntityDescription entityForName:@"TripTemplate" inManagedObjectContext:context]; 
[fetchRequest setPredicate:[NSPredicate predicateWithFormat:@"(productID = %@)", productID]]; 
[fetchRequest setEntity:entity]; 
NSError *error;
NSArray *fetchedObjects = [context executeFetchRequest:fetchRequest error:&error]; 
[fetchRequest release];

if ([fetchedObjects count] > 0) {
    TripTemplate *template = [fetchedObjects lastObject];
    template.purchased = [NSNumber numberWithBool:YES];

    NSLog(@"Marking '%@' as Purchased: %@", template.name, template.purchased);

    NSError *saveError;        
    if (![context save:&saveError])
        NSLog(@"Error Saving Purchased For Template: %@ - %@", template, saveError);
} else {
   ...
   //log fetch error
}
}

这是我在调用此方法时看到的两组日志。

我已经验证,在这两种情况下,它们都是从主线程调用的。

它们一个接一个地运行。

运行 #1(无 SQL 更新):

2011-04-30 17:25:27.107 App[15024:707] CoreData: sql: SELECT 0, t0.Z_PK, t0.Z_OPT, t0.ZLASTAPPSTOREPRICE, t0.ZPURCHASED, t0.ZISFREE, t0.ZNAME, t0.ZPRODUCTID, t0.ZSERVERID, t0.ZTRIPDESCRIPTION, t0.ZAUTHORDESCRIPTION, t0.ZAUTHORURL, t0.ZCREATEDAT, t0.ZAUTHORNAME 来自 ZTRIPTEMPLATE t0 WHERE t0.ZPRODUCTID = ?

2011-04-30 17:25:27.110 App[15024:707] CoreData:注解:sql连接获取时间:0.0028s

2011-04-30 17:25:27.111 App[15024:707] CoreData:注释:总提取执行时间:1 行 0.0043 秒。

2011-04-30 17:25:27.112 App[15024:707] 将“史蒂夫的创作”标记为已购买:1

运行 #2(SQL 更新):

2011-04-30 17:27:37.536 App[15024:707] CoreData: sql: SELECT 0, t0.Z_PK, t0.Z_OPT, t0.ZLASTAPPSTOREPRICE, t0.ZPURCHASED, t0.ZISFREE, t0.ZNAME, t0.ZPRODUCTID, t0.ZSERVERID, t0.ZTRIPDESCRIPTION, t0.ZAUTHORDESCRIPTION, t0.ZAUTHORURL, t0.ZCREATEDAT, t0.ZAUTHORNAME 来自 ZTRIPTEMPLATE t0 WHERE t0.ZPRODUCTID = ?

2011-04-30 17:27:37.537 App[15024:707] CoreData:注解:sql连接获取时间:0.0015s

2011-04-30 17:27:37.538 App[15024:707] CoreData:注释:总提取执行时间:1 行 0.0024 秒。

2011-04-30 17:27:37.539 App[15024:707] 将“史蒂夫的创作”标记为已购买:1

2011-04-30 17:27:37.540 App[15024:707] CoreData: sql: BEGIN EXCLUSIVE

2011-04-30 17:27:37.542 App[15024:707] CoreData: sql: UPDATE ZTRIPTEMPLATE SET ZPURCHASED = ?, Z_OPT = ?在哪里 Z_PK = ? AND Z_OPT = ?

2011-04-30 17:27:37.544 App[15024:707] CoreData: sql: COMMIT

有什么建议可以从哪里开始寻找我的问题?

在这两种情况下,获取都有效,因此看起来 MOC 至少能够与商店对话。

【问题讨论】:

  • 您是依靠 SQL 日志记录来告诉您没有任何更改,还是托管对象本身没有更改?重启时会出现变化吗?
  • 我只是使用 SQL 日志来验证。如果我在保存之前和之后记录购买的属性,它会显示为真,但如果我在保存后刷新对象,“购买”属性会恢复为假。
  • 您是否有多个上下文或多个线程/操作?
  • 在应用程序的其他部分,以及其他 MO,是的。我们在这里讨论的所有交互(以及一般的这种类型的 MO)仅在主线程上进行交互。一般来说,我对每个线程一个 MOC 非常小心,所以虽然我搞砸了并非不可能,但这也不是我的第一个 Core Data 线程圈。
  • 好吧,我问是因为直接 SQL 是一个不确定的工具,无法与 Core Data 一起使用,因为 API 并不总是像你认为的那样,如果它只是一个 SQL 包装器。许多优化似乎阻止了您可能期望的读取和写入。但是,如果对象本身还原,则不会保存更改。

标签: iphone core-data nsmanagedobjectcontext


【解决方案1】:

在查看代码时,我唯一可以建议的错误是您以某种方式将不同的上下文传递给该方法。如果是这样,并且您没有合并上下文,那么如果您保存在一个中但从另一个中检查,则不会显示更改。

我建议记录整个模板对象、上下文和上下文的更新对象。您需要确保您正在与您认为自己是的对象交谈。

【讨论】:

  • 听起来值得仔细检查。我一直在看这个这么久,我的大脑正在融化,那时我开始做出危险的假设。将报告...
  • 这是个好建议。原来我在一个代码路径中混合了传递给方法的 MOC,这导致了这种奇怪。因此,事实证明这是非常简单的用户错误案例。有时你只需要和某人谈谈。谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-09-19
相关资源
最近更新 更多