核心数据 - 放弃更改

时间:2011-10-19 16:43:05

标签: objective-c core-data model

希望有人能解释发生了什么。

如果我从Core Data模型中获取了一个对象,请修改一个不持久或甚至在模型中定义的属性!然后再次销毁并获取对象,该值仍然是先前设置的。

为什么会这样?

Promotion *promotion = [Promotion promotionWithId:[NSNumber numberWithInt:1512] inManagedObjectContext:context];
    [promotion setQuantity:[NSNumber numberWithInt:2]];
    NSLog(@"%d", [promotion.quantity intValue]);
    promotion = nil;

    promotion = [Promotion promotionWithId:[NSNumber numberWithInt:1512] inManagedObjectContext:context];
    NSLog(@"%d", [promotion.quantity intValue]);
    promotion = nil;

输出是:

2 2

供参考:

+(Promotion *)promotionWithId:(NSNumber *)promotionId inManagedObjectContext:(NSManagedObjectContext *) context {
    NSFetchRequest *fetchReq = [[NSFetchRequest alloc]init];
    [fetchReq setEntity:[NSEntityDescription entityForName:@"Promotion" inManagedObjectContext:context]];

    NSPredicate *query = [NSPredicate predicateWithFormat:@"promotionId=%d", [promotionId intValue]];
    [fetchReq setPredicate:query];

    NSMutableArray *resultArray = [[NSMutableArray alloc]initWithArray:[context executeFetchRequest:fetchReq error:nil]];

    if([resultArray count] > 0) {
        return [resultArray objectAtIndex:0];
    }

    return nil;
}

3 个答案:

答案 0 :(得分:24)

请记住,您对所有托管对象所做的更改将保留在Coredata的托管对象上下文中,直到您将其保留(即保存上下文)。

因此,在您的情况下,您正在对托管对象进行更改,将其引用设置为nil但不重置上下文。

这意味着您的更改仍然有效,下次您获取相同的对象时,它将被应用。

要完全摆脱它,您需要使用以下命令重置上下文:

[context reset];

来自NSManagedObjectContext重置方法文档:

  

所有接收者的管理对象都被“遗忘”。如果你使用它   方法,你应该确保你也放弃对any的引用   使用接收器获取的托管对象,因为它们将无效   之后。

答案 1 :(得分:6)

Core Data缓存对象,缓存可能会保留未定义属性的ivars。

尝试[context refreshObject:promotion mergeChanges:NO]然后尝试日志声明。

答案 2 :(得分:0)

您在代码中有几个错误,我试图解释RestKit邮件列表上发生了什么。让我在这里粘贴答案(进行一些修正以使文本更容易理解)。


当然,托管对象上下文甚至不知道模型中未定义的属性,也不是持久对象库。因此,必须有别的东西。

让我们来看看你的代码。你打了promotion = nil; - 没有释放对象。在代码的那一部分中,您没有泄漏,但该对象未在该阶段释放。该对象由resultArray持有。

那么对象何时被释放?它将与resultArray一起发布。您没有释放resultArray中分配的+promotionWithId:inManagedObjectContext:你根本没有释放它。似乎没有理由首先将结果数组转换为可变数组。

解决方案的两个变体:

NSArray *resultArray = [context executeFetchRequest:fetchReq error:nil];

NSMutableArray *resultArray = [[NSMutableArray alloc] initWithArray:[context executeFetchRequest:fetchReq error:nil]];
[resultArray autorelease];

这些都是自动释放的对象。如果你去自动释放路线,一旦最近的自动释放池被排空或释放,对象就会被释放。您可以通过将代码包装在以下内容来添加自动释放池:     NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; 和     [池发布];

如果没有这个,最近的自动释放池可能在Cocoa主运行循环中。因此,resultArray(以及因此产生的对象)将在Cocoa主运行循环中释放。

您可能希望直接在resultArray内发布+promotionWithId:inManagedObjectContext:,但在保留和自动释放之前不会[resultArray objectAtIndex:0];

那么,释放对象时会发生什么?希望它应该从托管对象上下文中删除,然后任何提取的副本都应该是一个错误(因为原来的那个是,或者应该消失)。坦率地说,我很惊讶,首先返回对象的相同副本(并且感谢问这个问题) - 但这只是合乎逻辑的,因为Core Data只是一个对象图管理器,方便地随附高性能持久层。

您也可以手动将对象变为故障: http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/CoreData/Articles/cdFaultingUniquing.html

希望这有帮助!