未保存Transient属性的setPrimitiveValue

时间:2015-04-21 12:15:42

标签: ios iphone core-data

我在我的NSManagedObject上使用了一些Transient属性来预先计算在依赖属性更新时只需要计算一次的东西,但是当我重置Transient属性上的值时,它永远不会被保存。

例如:

-(NSString*)age {
    // notify core data to access value
    [self willAccessValueForKey:@"age"];
    // get primitive value
    NSString* age = [self primitiveValueForKey:@"age"];
    // is age already exist?
    if ( age == nil ) {
        // get age
        age = [GlobalHelper convertToAgeStringWithUTCDateOfBirth:(NSString*)self.dateOfBirth];
        // set primitive value
        [self setPrimitiveValue:age forKey:@"age"];
    }
    // notify core data done access value
    [self didAccessValueForKey:@"age"];
    return age;
}

-(void)setDateOfBirth:(id)dateOfBirth {
        // change value for key
        [self willChangeValueForKey:@"dateOfBirth"];
        [self willChangeValueForKey:@"age"];
        // set primitive
        [self setPrimitiveValue:dateOfBirth forKey:@"dateOfBirth"];
        [self setPrimitiveValue:nil forKey:@"age"];
        // did change value for key
        [self didChangeValueForKey:@"age"];
        [self didChangeValueForKey:@"dateOfBirth"];
}

从上面的代码可以看出,当我同步这个对象并且“dateOfBirth”字段被更新时,它尝试将“age”设置为“nil”并且当访问“age”字段时它是否为“nil” “然后计算年龄,再也不计算它。

然而问题是当我在“setDateOfBirth”设置中将“age”字段设置为“nil”时它从未保存过,当我再次访问age时,“age”属性仍然具有之前的值,但“dateOfBirth”已更新。

非常感谢与此主题远程相关的任何帮助,我对此有很大的麻烦......

编辑:上面提到的逻辑在同一个上下文(相同的线程上下文)中setter和getter调用的情况下都是完美的,只有当从具有私有队列的AFNetworking api的完成块调用setter并且从主线程调用getter时才会出现问题合并后。

似乎当我从AFNetworking完成阻止的上下文保存时,它只保存dateOfBirth而不是它设置为nil的年龄值,因此在合并之后以及当主线程“age”的getter调用具有之前的值时所以它再也不会计算了。

1 个答案:

答案 0 :(得分:1)

阅读年龄时,不应设定年龄。这似乎是非常奇怪的设计,也无法调用适当的键值编码通知。

而是遵循您原来的逻辑:如果出生日期发生变化,请更新年龄。您应该在setDateOfBirth中执行此操作,并在age的设置器中调用相应的键值编码通知。

-(void) setDateOfBirth:(id)newValue {
    [self willChangeValueForKey:@"dateOfBirth"];
    [self setPrimitiveValue:newValue forKey:@"dateOfBirth"];
    [self didChangeValueForKey:@"dateOfBirth"];

    self.age = [GlobalHelper 
       convertToAgeStringWithUTCDateOfBirth:(NSString*)newValue];
}

-(void)age {
  [self willAccessValueForKey:@"age"];
  NSString* age = [self primitiveValueForKey:@"age"];
  [self didAccessValueForKey:@"age"];
  if (age == nil) {
      age = [GlobalHelper 
         convertToAgeStringWithUTCDateOfBirth:(NSString*)self.dateOfBirth];
  }
  self.age = age;
  return age;
}

然而,尽管如此,你必须问自己convertAge电话的确有多贵。在除了最极端的情况之外的所有情况中,实际上只需要一个进行转换的简单吸气剂。

另外,我认为您的dateOfBirth属性应该具有标准的托管对象属性类型,而不是id。它是一个字符串?然后你应该将它声明为NSString,而不是使用id和强制转换。