7

假设我有一个带有只读属性的类。

//MyClass.h
@interface MyClass

@property (readonly) NSInteger MonitorMe;

@end

现在,让我们假设该属性的目的是监视另一个对象内另一个属性的变化,并且当“观察”该属性时,它通过检查来自另一个外部对象的值来返回派生值。

//MyClass.m
@implementation

@synthesize MonitorMe;
-(NSInteger) getMonitorMe
{
    return globalStaticClass.OtherNSInteger;
}

... Inits and Methods ...
@end

现在,让我们假设在某些地方我创建了一个MyClass对象的实例,并且我想在该MonitorMe属性上添加一个 KVO 观察者。

//AnotherClass.m
@implementation AnotherClass.m

    @synthesize instanceOfMyClass;

    -(id)init
    {
        ...
        instanceOfMyMethod = [MyClass init];
            [MyClass addObserver: self 
                  forKeyPath: @"MonitorMe" 
                     options: NSKeyValuObservingOptionNew
                     context: nil];
        ...
    }

我的问题是,由于该MonitorMe属性只监视外部对象中值的变化,所以观察者方法会在值globalStaticClass.OtherNSInteger变化时执行吗?另外,如果答案是肯定的,这是如何完成的?

如果这行得通,对我来说这似乎是编译器巫术。

笔记

我不认为这有什么区别,但我正在使用 ARC 来实现这个实现,并且我正在为 iOS 设备进行编译。对于这类问题,我怀疑 OS X 和 iOS 之间存在编译差异,但如果重要的话,我有一个 iOS 项目需要上面概述的这种实现。

此外,上面概述的示例是我实际需求的一个非常基本的设置。可以说我可以/应该向值添加观察globalStaticClass.OtherNSInteger值而不是只读属性,MonitorMe. 在我的实际情况下,这个答案是不够的,因为我的只读属性比我的例子复杂得多。

4

1 回答 1

8

globalStaticClass.OtherNSInteger当值发生变化时,观察者方法会执行吗?

不,但是您可以通过+keyPathsForValuesAffectingMonitorMe(或更通用的+keyPathsForValuesAffectingValueForKey:,如果“globalStaticClass”实际上是 MyClass 的属性,则可以做到这一点。请参阅KVO 指南中的“注册依赖键”

这是一个快速模型:

#import <Foundation/Foundation.h>

@interface Monitored : NSObject 
@property NSInteger otherInteger;
@end

@implementation Monitored
@synthesize otherInteger;
@end

@interface Container : NSObject 
@property (readonly) NSInteger monitorMe;
@property (strong) Monitored * theMonitored;

- (void)changeMonitoredInteger;
@end

@implementation Container

@synthesize theMonitored;

+ (NSSet *)keyPathsForValuesAffectingMonitorMe {

    return [NSSet setWithObject:@"theMonitored.otherInteger"];
}

- (id) init {

    self = [super init];
    if( !self ) return nil;

    theMonitored = [[Monitored alloc] init];
    [theMonitored setOtherInteger:25];

    return self;
}

- (NSInteger)monitorMe
{
    return [[self theMonitored] otherInteger];
}

- (void)changeMonitoredInteger {

    [[self theMonitored] setOtherInteger:arc4random()];
}

@end

@interface Observer : NSObject 
@end

@implementation Observer

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {

    NSLog(@"Observing change in: %@ %@", keyPath, object);
}

@end

int main(int argc, const char * argv[])
{

    @autoreleasepool {

        Observer * o = [[Observer alloc] init];
        Container * c = [[Container alloc] init];

        [c addObserver:o
            forKeyPath:@"monitorMe"
               options:NSKeyValueObservingOptionNew
               context:NULL];

        [c changeMonitoredInteger];
        [c changeMonitoredInteger];

    }
    return 0;
}

PS Cocoa 风格注释:属性/变量应该有小写首字母,并且(由于 ARC,这实际上现在更重要)不要以“get”开头命名访问器方法——这在 Cocoa 中具有特定含义,涉及传入缓冲区并通过引用获取数据。

于 2012-05-04T20:13:07.520 回答