【发布时间】: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