2012-10-01 27 views
10

如果任何受监视的对象属性被修改,是否可以添加观察者以获得通知?例如:整个对象属性的KVO

@interface OtherObject : NSObject 

@property (nonatomic) MyObject* myObject; 

@end 

@interface MyObject : NSObject 

@property (nonatomic) unsigned int property1; 
@property (nonatomic) unsigned int property2; 

@end 

我想这样做:

[otherObject addObserver:self 
       forKeyPath:@"myObject" 
        options:0 
        context:nil] 

如果任一property1或property2被修改得到通知。如果我注册了保持对象,它似乎不起作用(某种程度上是有道理的,因为myObject在修改property1时没有真正修改)。

回答

12

我可以考虑两种选择。

  • 您可以创建一个单独的“主”属性,并使其依赖于所有其他属性。

    @interface MyObject : NSObject 
    @property (nonatomic) id masterProperty; 
    @property (nonatomic) unsigned int property1; 
    @property (nonatomic) unsigned int property2; 
    @end 
    

    + (NSSet *)keyPathsForValuesAffectingMasterProperty { 
        return [NSSet setWithObjects:@"property1", @"property2", nil]; 
    } 
    

    如果你观察masterProperty您会收到通知的任何性质的改变。

  • 您可以使用Objective-C运行时获取所有属性的列表,并观察它们全部。

    - (void)addObserverForAllProperties:(NSObject *)observer 
              options:(NSKeyValueObservingOptions)options 
              context:(void *)context { 
        unsigned int count; 
        objc_property_t *properties = class_copyPropertyList([self class], &count); 
        for (size_t i = 0; i < count; ++i) { 
         NSString *key = [NSString stringWithCString:property_getName(properties[i])]; 
         [self addObserver:observer forKeyPath:key 
            options:options context:context]; 
        } 
        free(properties); 
    } 
    
+0

假设你也可以结合这两种方法,使用Objective-C运行时获得keyPathsForValuesAffectingMasterProperty中所有属性的列表,然后在NSSet中返回它们。 (使用静态变量可能是个好主意,所以你只需要做一次。) – dgatwood

2

你可以做的是有一个功能修改myObject的的特定属性...

-(void)setMyObjectName:(NSString*)name; 

,然后在功能有这样的代码......

- (void)setMyObjectName:(NSString*)name 
{ 
    [self willChangeValueForKey:@"myObject"]; 

    myObject.name = name; 

    [self didChangeValueForKey:@"myObject"]; 
} 

这将然后在myObject上的属性发生更改时通知观察者。

无论你需要这样做,使用这种模式,你可以得到通知任何改变myObject。

::编辑:: 说了这么多,你应该能够使用...

[otherObject addObserver:self 
       forKeyPath:@"myObject.property1" 
       options:0 
       context:nil]; 

,并且将遵守property1做同样堡的其他属性。

但是,这意味着要为每个属性单独添加一个观察者。

+0

也许willChangeValueForKey willChangeObjectForKey的呢? – Andy

+1

@安迪变了。惊讶的是,虽然两年没有发现。大声笑! – Fogmeister