为啥我的 ivar 没有在 NSManagedObject 子类上设置

Posted

技术标签:

【中文标题】为啥我的 ivar 没有在 NSManagedObject 子类上设置【英文标题】:Why is my ivar not getting set on NSManagedObject Subclass为什么我的 ivar 没有在 NSManagedObject 子类上设置 【发布时间】:2014-02-02 20:47:04 【问题描述】:

我有一个使用 CoreData 的项目。我使用 Mogenerator 生成子类。

当我设置一个属性的值时,这个值实际上并没有被赋值。以后每次我尝试设置该值时,我之前设置的值都没有被赋值。

这很好用,因为我的底层数据框架是 Mantle,但是自从迁移到 CoreData 后,它就停止了工作。我依靠 KVO 使一些 UIView 对象与模型保持同步。

同样,CoreData NSManagedObject 子类的 ivars 似乎没有采用我分配给它们的值。

考虑如下界面:

@interface Light : _Light

/**
 Light / Color Properties
 */
@property (nonatomic, assign) CGFloat brightness; // 0...1
@property (nonatomic, assign) CGFloat hue;  // 0...1
@property (nonatomic, assign) CGFloat saturation;  // 0...1
@property (nonatomic, assign, getter = isEnabled) BOOL enabled;

@property (nonatomic, readonly) UIColor *color;  // derived from the above 

- (void)setHue:(CGFloat)hue saturation:(CGFloat)saturation;  // it often makes sense to set these together to generate fewer KVO on the color property.
@end

以及以下 .m 文件:

@interface Light ()
    
    CGFloat _hue, _saturation, _brightness;

    UIColor *_color;  

@property (nonatomic, assign) BOOL suppressColorKVO;
@property (nonatomic, readwrite) UIColor *color;
@end

@implementation Light

@synthesize suppressColorKVO = _suppressColorKVO;

- (void)setHue:(CGFloat)hue saturation:(CGFloat)saturation

    BOOL dirty = NO;
    if (saturation != _saturation) 
        // clamp its value
        [self willChangeValueForKey:@"saturation"];
        _saturation = MIN(MAX(saturation, 0.0f), 1.0f);
        [self didChangeValueForKey:@"saturation"];
        dirty = YES;
    
    if (hue != _hue) 
        [self willChangeValueForKey:@"hue"];
        _hue = MIN(MAX(hue, 0.0f), 1.0f);
        [self didChangeValueForKey:@"hue"];
        dirty = YES;
    
    if (dirty) 
        if (!_suppressColorKVO) 
            [self setColor: self.color];
        
    


// other stuff... the color accessors are also custom.  Derived from the h, s, b values.

@end

我认为我对 CoreData 不满意,但我不知道出了什么问题。这些色调、饱和度、亮度都是“瞬态的”(不是核心数据意义上的),因为它们会被我们与之交互的某些硬件不断更新,因此无需保存它们的状态。

【问题讨论】:

'[self setColor:self.color]' 是什么意思?看起来很奇怪,你覆盖了颜色getter方法吗? 是的,别担心。 ;-) 两者都是自定义的,我这样做是因为颜色是派生的,而 setColor 会发送 KVO。那不是问题。它工作得很好。是 ivars 没有保持我为它们设置的值。 【参考方案1】:

如果 huesaturation 是模型中的属性,那么您应该使用 setPrimitiveValue:forKey:(或相关的生成的原始方法)设置它们的值。

也就是说,您的代码看起来都是自定义的,因为模型属性将是 NSNumber 实例,并且 mogenerator 会为您创建值方法。所以我猜测你拥有的这些属性在模型中没有得到支持,这就是它们没有被存储的原因。

因此,将属性添加到模型并使用适当的方法访问值。

【讨论】:

我会在今天晚些时候处理它时这样做。根本不是 CoreData 专家,您是说将我自己的 ivars 保持在“CoreData 模型之外”(即不声明,并由我自己的访问器管理,就好像它是 NSObject 的直接子类一样)不起作用?我更愿意这样做,因为它们真的太临时了,我想把 CoreData 排除在外。 托管对象不是这样设计的。如果你想这样做,你应该使用一个普通的对象。 不能使用普通对象。无论如何,为了真正追查这个问题的根源,我采取了这个问题行为,将其与我的应用程序的其余功能隔离,将其放入测试/沙箱项目中,并注意到我没有看到问题了。所以我猜我上面描述的问题并不是全部。当我找到问题的根源时,我会更新。【参考方案2】:

最终它与CoreData无关。上面的这种方法确实适用于 CoreData 对象。您可以在子类中拥有一些存在于 CoreData NSManagedObject 之外的“瞬态”属性,并且您可以为它们创建自己的 ivars,以及您自己的访问器,并且它可以合作。

关于这个问题,我有一个复杂的系统,它也向某些硬件发送一些命令,硬件返回响应是否接受当前状态的命令。事实证明我在那个处理程序中有一个错误,它将这些值设置回一些意外的值。

帮助我调试它的是在调试器中使用观察点。非常方便的功能!您设置了一个观察点,只要变量的内存地址设置为新值,它就会在调试器中中断。 (一点点more on that here)

【讨论】:

以上是关于为啥我的 ivar 没有在 NSManagedObject 子类上设置的主要内容,如果未能解决你的问题,请参考以下文章

为啥在 init 方法中为 iVar 定义调用 autorelease?

如果 @protected 是默认值,为啥这个 ivar 需要 @protected?

为啥/何时应该使用静态声明变量?

属性和 ivars 的问题

UIScrollView 委托如何知道我的 UIScrollView ivar?

核心数据的 Objective C 属性与 ivar 问题