保存父上下文忽略对保存到子上下文的瞬态属性的编码值的更改

时间:2013-08-22 11:46:51

标签: ios macos cocoa core-data nsmanagedobjectcontext

核心数据文本资产有一个瞬态属性textStorage,该属性会持续保存在contents类型NSData中。在某些情况下,在编辑textStorage核心数据后保存上下文不会保存更改。该应用正在使用BSManagedDocument与父管理对象上下文一起保存在后台。下面是一个伪日志,用于说明正在发生的事情。预计第二个日志将被持久保存,但父上下文将恢复为原始日志。

这是我在TextAsset实现中选择处理编码/解码的方式吗?(见下文)?

文本存储日志

编辑前的原始文本存储:

Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit.
THIS GETS DELETED
Donec ullamcorper nulla non metus auctor fringilla.

子级(主要文档)上下文中willSave:的文本存储(在文本视图中编辑后):

Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit.
Donec ullamcorper nulla non metus auctor fringilla.

父级(背景保存)上下文中willSave:的文本存储(保存子级上下文后):

Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit.
THIS GETS DELETED
Donec ullamcorper nulla non metus auctor fringilla.

正如你所看到的那样,“删除已删除”行仍在那里。

TextAsset.m实现的相关部分

+ (NSSet *)keyPathsForValuesAffectingValueForKey:(NSString *)key 
{
    NSSet *keyPaths = [super keyPathsForValuesAffectingValueForKey:key];

    if ([key isEqualToString:@"contents"]) {
        return [keyPaths setByAddingObject:@"textStorage"];
    }

    return keyPaths;
}

- (void)setTextStorage:(NSTextStorage *)textStorage {
    [self willChangeValueForKey:@"textStorage"];
    [self setPrimitiveValue:textStorage forKey:@"textStorage"];
    [self didChangeValueForKey:@"textStorage"];
}

- (NSTextStorage *)textStorage 
{    
    [self willAccessValueForKey:@"textStorage"];
    NSTextStorage *textStorage = [self primitiveValueForKey:@"textStorage"];
    [self didAccessValueForKey:@"textStorage"];

    if (textStorage == nil) {
        NSData *contents = [self contents];
        if (contents != nil) {
            textStorage = [NSKeyedUnarchiver unarchiveObjectWithData:contents];
            [self setPrimitiveValue:textStorage forKey:@"textStorage"];
        }
    }
    return textStorage;
}

- (void)willSave 
{
    NSTextStorage *textStorage = self.textStorage;

    if (textStorage != nil) {
        [self setPrimitiveContents:[NSKeyedArchiver archivedDataWithRootObject:textStorage]];
    }
    else {
        [self setPrimitiveContents:nil];
    }

    [super willSave];
}

1 个答案:

答案 0 :(得分:0)

进一步研究后发现,当子上下文中对象的contents值在保存时被推送到父对象时,会导致问题。如果父上下文中的托管对象仍在内存中,则它本身仍将在内存中具有瞬态textStorage。因此,使用上面的代码,它只会再次归档textStorage,而不是使用更新的contents

通过重置textStorage时(基元)contents更改,可以避免此行为。