核心数据不会持续对数据库的属性更新

时间:2011-04-12 00:15:41

标签: iphone cocoa-touch ios core-data nsmanagedobject

我正在使用NSManagedObject的子类。实际上,它继承自一个继承自NSManagedObject的类的类(这应该不是问题,对吗?)。

问题

在更改对象的属性后,对象会记住其生命周期的更改,但更改永远不会保存到数据库中。

我如何知道?

我知道这是因为:

  • 当我重新启动应用时,我所做的更改将丢失。
  • 告诉上下文刷新对象 - 在我对对象进行了更改并告诉上下文保存之后 - 在我进行更改之前将对象的值设置回原始状态。
  • 在模拟器中运行应用程序时,我可以查看Finder中的sqlite数据库文件,当我尝试保存上下文时,它的修改日期不会更新。

没有任何内容写入数据库!

上下文

我正在使用自动生成的委托方法来创建商店协调员和上下文。然后我按照文档中的建议将上下文传递给它们的init方法中的视图控制器。这家商店是SQLite。

我能够成功地将对象插入数据库并读取它们。我甚至可以对新插入的对象进行属性更改并成功保存。当对象被拉出数据库时,我似乎无法更新对象属性。

通过来自另一个对象的关系从商店中获取对象。在更改其属性后,我调用上下文的save方法。但是,在这样做之前,我调用对象的isUpdated方法和上下文的hasChanges方法,并且都返回false。它们不应该返回true,因为我刚刚更改了对象的属性但没有保存上下文吗?

更多

如果我在保存上下文之前调用对象的committedChanges方法,但是,传入我已更改的属性的名称,我会返回属性的正确值。我不确定这意味着什么。我原本以为这意味着对象的新属性值已成功保存,但很明显它们没有保存。

我知道结果对象是在上下文中注册的。如果我打电话

[[result managedObjectContext] refreshObject:result mergeChanges:YES];

对象恢复为原始属性值。这意味着上下文存在,并且它是从中获取记录的相同上下文。这意味着新属性值永远不会写入数据库。

部分代码

这是我正在探讨所有这些事情的代码。

我的代码中还有其他地方可以更改属性,但更改永远不会保存。

- (IBAction)statusControlChanged:(UISegmentedControl *)control {
WCAAssessmentResult *result = [self currentResult];

    /* printing the existing property values */
    if (![result.complete boolValue]) NSLog(@"result is in progress!");
    else if ([result.passed boolValue]) NSLog(@"result is passed!");
    else NSLog(@"result is not passed!");

    /* changing the property values */
    switch (control.selectedSegmentIndex) {
        case 0:
            NSLog(@"setting incomplete");
            result.complete = [NSNumber numberWithBool:NO];
            break;
        case 1:
            NSLog(@"setting passed");
            result.passed = [NSNumber numberWithBool:YES];
            result.complete = [NSNumber numberWithBool:YES];
            break;
        case 2:
            NSLog(@"setting failed");
            result.passed = [NSNumber numberWithBool:NO];
            result.complete = [NSNumber numberWithBool:YES];
            break;
        default:
            break;
    }

    /* this method always returns an empty dictionary */
    NSLog(@"%@", [result changedValues]);

    /* this method returns the values that I just set */
    NSLog(@"%@", [result committedValuesForKeys:[NSArray arrayWithObjects:@"complete", @"passed", nil]]);

    /* isUpdated returns false */
    if (![result isUpdated]) {
        NSLog(@"result is not updated?! WTF!?!?");
    }

    /* hasChanges returns false */
    if (![[result managedObjectContext] hasChanges]) {
        NSLog(@"context has no changes!? WTF!?!?");
    }

    /* saving the context produces no error */
    NSError *error = nil;
    if (![[result managedObjectContext] save:&error]) {
        NSLog(@"save failed");
        NSLog(@"%@",[error description]);
    }
}

扭曲

如果我通过在上下文中插入新记录来创建新的结果对象,我可以设置该对象的属性并成功保存。在上面的代码中,我将对象作为来自另一个对象的多对象关联的成员。这是一个线索吗?

我正在撕裂我的头发。这到底怎么可能出错?

什么不是问题

  • 我已经记录了对象的类,它确实是正确的类
  • 我确保我保存的managedObjectContext与对象的上下文相同
  • 我没有对托管对象类的自动生成的setter / getter方法进行任何更改
  • 我尝试过使用setValue:forKey:方法而不是对象的属性
  • 我使用-com.apple.CoreData.SQLDebug 1参数记录Core Data SQL,当我更新并保存对象的属性时没有记录SQL

2 个答案:

答案 0 :(得分:3)

我真的不明白你的陈述

WCAAssessmentResult *result = [self currentResult];

实际上,如果要从对象访问多对多关系,则应该返回一个集合,而不是对象。无论如何,没有看到代码,很难说。您遇到的问题可能存在,也可能不存在。

我宁愿在您的代码中期望类似以下代码段来访问属于多对多关系的对象。我假设yourObject是您用来访问多对多关系中WCAAssessmentResult个对象的对象,我称之为results

NSMutableSet *resultObjects = [yourObject mutableSetValueForKey:@"results"];
NSPredicate *predicate = ...
[resultObjects filterUsingPredicate:predicate];

for(WCAAssessmentResult *result in resultObjects){

   // modify as needed the current result object

}

NSError *error = nil;
if (![managedObjectContext save:&error]) {
        NSLog(@"save failed");
        NSLog(@"%@",[error description]);
}

您是否验证了用于保存对象的managedObjectContext是否有效(不是nil)?

答案 1 :(得分:0)

一些想法没有特别的顺序:

我会记录result对象的类,并确保它是您认为的类。与超级/子类的某些混淆可能导致某些值未被保存。

如果您对层次结构中的任何类中的setter / getter方法进行了任何更改,请仔细查看这些方法,尤其是在使用primativeValue方法时。简单地省略willChangeValuedidChangeValue可能会导致更改对上下文不可见,有时也会对对象本身不可见。

我会记录您保存的上下文以及managedObjectContext对象的result属性。确认它们确实是相同的背景。

使用属性访问器(点符号)跳过并使用setValue:forKey,看看是否有任何区别。如果是这样,您有一个访问者问题。同样,您可以尝试setPrimativeValue:forKey来检查访问者问题。

如果我必须下注,我会把钱花在你将fetch返回的对象分配给错误的类。