Objective c 传递到observeValueForKeyPath的一对多但NSNull对象的KVO

Objective c 传递到observeValueForKeyPath的一对多但NSNull对象的KVO,objective-c,ios,ios5,key-value-observing,Objective C,Ios,Ios5,Key Value Observing,我有一个与成员类具有一对多关系的托管对象。当我为成员添加观察员时,它起了作用。将一个新成员添加到关系中时,将使用新对象调用observeValueForKeyPath,并且更改字典包含新成员对象。但是,observeValueForKeyPath将使用所有值nil和change dictionary new=“NULL”再次触发。第二个触发器是什么?我设置了一个断点,但不确定是谁触发的 @interface FooObject : NSManagedObject {} @property (no

我有一个与成员类具有一对多关系的托管对象。当我为成员添加观察员时,它起了作用。将一个新成员添加到关系中时,将使用新对象调用observeValueForKeyPath,并且更改字典包含新成员对象。但是,observeValueForKeyPath将使用所有值nil和change dictionary new=“NULL”再次触发。第二个触发器是什么?我设置了一个断点,但不确定是谁触发的

@interface FooObject : NSManagedObject {}
@property (nonatomic, strong) NSString *fooId;
@property (nonatomic, strong) NSSet* members;
@end

@implementation FooObject
@dynamic fooId;
@dynamic members;

- (NSMutableSet*)membersSet {
    [self willAccessValueForKey:@"members"];

    NSMutableSet *result = (NSMutableSet*)[self mutableSetValueForKey:@"members"];

    [self didAccessValueForKey:@"members"];
    return result;
}

- (void)registerObservers {
    [self addObserver:self
           forKeyPath:@"members"
              options:NSKeyValueObservingOptionNew
              context:nil];
}

- (void)unregisterObservers {
    @try{
        [self removeObserver:self forKeyPath:@"members"];
    }@catch(id anException){
        //do nothing, obviously it wasn't attached because an exception was thrown
    }
}

- (void)observeValueForKeyPath:(NSString *)keyPath
                      ofObject:(id)object 
                        change:(NSDictionary *)change 
                       context:(void *)context
    id valueNewSet = [change objectForKey:NSKeyValueChangeNewKey];
    if (![valueNewSet isKindOfClass:[NSSet class]]) {
            // not a NSSet, it contains <null> value
            NSLog(@"%@", change);
            NSLog(@"%@", object);
    }
    if ([[change objectForKey:NSKeyValueChangeKindKey] intValue] == NSKeyValueChangeInsertion) {
           // insert change is valid, process the changes
    }

}
@end
@接口对象:NSManagedObject{}
@属性(非原子,强)NSString*fooId;
@属性(非原子,强)NSSet*成员;
@结束
@对象的实现
@动态食物;
@动态成员;
-(NSMutableSet*)成员集{
[自愿访问价值观:成员];
NSMutableSet*结果=(NSMutableSet*)[self-mutableSetValueForKey:@“members”];
[self-didAccessValueForKey:@“成员”];
返回结果;
}
-(无效)注册观察服务器{
[自我添加观察员:自我
forKeyPath:@“成员”
选项:NSKeyValueObservingOptionNew
上下文:无];
}
-(无效)未注册观察员{
@试一试{
[self-removeObserver:self-forKeyPath:@“成员”];
}@捕获(id为异常){
//不执行任何操作,显然它没有附加,因为引发了异常
}
}
-(void)observeValueForKeyPath:(NSString*)键路径
ofObject:(id)对象
更改:(NSDictionary*)更改
上下文:(void*)上下文
id valueNewSet=[change objectForKey:NSKeyValueChangeNewKey];
如果(![valueNewSet isKindOfClass:[NSSet class]]){
//不是NSSet,它包含值
NSLog(@“%@”,变更);
NSLog(@“%@”,对象);
}
if([[change objectForKey:NSKeyValueChangeKindKey]intValue]==NSKeyValueChangeInsertion){
//插入更改有效,请处理更改
}
}
@结束
日志输出:

{
    kind = 1;
    new = "<null>";
}

<FooObject: 0xfa9cc60> (entity: FooObject; id: 0xfa9be00 <x-coredata://39DB31FD-6795-4FDE-B700-819AB22E5170/SHInterest/p6> ; data: {
    fooId = nil;
    members = nil;
})
{
种类=1;
新=”;
}
(实体:FooObject;id:0xfa9be00;数据:{
fooId=零;
成员=零;
})
编辑1 我在NSLog上设置了一个断点(@“%@”,change); 这是堆栈跟踪,但对于确定是谁进行了此调用没有实际帮助

main->UIApplicationMain->NSKeyValueNotifyObserver->observeValueForKeyPath:对象:更改:上下文

编辑2 也许这仍然是一个bug?

我遇到了同样的问题,“隐式”分配(以及KVO观察者的通知)显然只是作为解除分配MOs的一部分发生的:我保存一个子MOC,然后释放它,然后iOS释放它的MOs。我假设在解除分配相关MOs的过程中(删除规则级联适用),它会将一对多关系临时设置为
NSNull


因此,接下来要更改插入和删除的种类,我的KVO observer现在也接受
NSKeyValueChangeSetting
并断言
change[NSKeyValueChangeNewKey]==NSNull.null
。称之为务实的解决方案。

当您在断点处停止时,它应该会显示堆栈跟踪。这应该包含一些关于为什么调用它的线索。是的,但是堆栈跟踪一点帮助都没有。我更新了跟踪。这里的复杂因素是,你观察到的不是一个单一的值,而是一种关系。从文档中可以看到:“如果观察到的属性是一个对多关系,则NSKeyValueChangeKindKey条目还指示是否通过分别返回NSKeyValueChangeInsertion、NSKeyValueChangeRemovement或NSKeyValueChangeReplacement来插入、删除或替换关系中的对象。”@Elisevanloij But new=“”使用NSKeyValueChangeKindKey=NSKeyValueChangeSetting时,设置似乎不正确。所以这是一个bug?在这里,我发现当一个方法返回一个
NSNull
对象时,该对象上的-description返回字符串
,所以这不是bug。您可以像这样检查
nil
如果([change objectForKey:NSKeyValueChangeNewKey]==nil | |[change objectForKey:NSKeyValueChangeNewKey]==(id)[NSNull null]){…