KVO在运行之前具有未知的观察对象

时间:2011-04-02 21:53:25

标签: iphone objective-c reflection key-value-observing

我有一个“Compass”类,它是另一个类“SensorA”,“SensorB”或“SensorC”的观察者。问题是我在运行时之前不知道观察到的类。我使用反射来在运行时创建实例。 我不知道在这样做时我是否正确地练习KVO。


---Another Extern Class---
Compass *aCompass= [[AnalogCompass alloc] initWithCompassName:@"ABC" andID...];

---The oberserving Compass.m Class---
- (id)initWithCompassName:(NSString *)CompassName
                     andIid:(int)Iid

                     showAnalog:(NSString *)ShowAnalog
                     showDigital:(NSString *)ShowDigital

{
    if (self = [super init])
    {

        super.iid = Iid;
        super.CompassName = CompassName;

        showAnalog=ShowAnalog;
        showDigital=ShowDigital;

        Class unknown_cls;

        unknown_cls = [[NSClassFromString(super.CompassName) alloc]init];

        [unknown_cls addObserver:self forKeyPath:showAnalog options:NSKeyValueObservingOptionNew context:NULL];
        [unknown_cls addObserver:self forKeyPath:showDigital options:NSKeyValueObservingOptionNew context:NULL];
}  
 }


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

    NSLog(@"IN?");

//             [super observeValueForKeyPath:keyPath
//   
//                         ofObject:object
//   
//                           change:change
//   
//               context:context];

}


---Example of the oberserved SensorA Class---
@interface SensorA : NSObject { 

double xPosition;
...
}

@property (assign) double depthInFeet;

- (id)initWithLineToParse:(NSArray *) fields;

@end

当我做出改变时 self.xposition = position; 在我的任何观察和反射的传感器类(SensorA,SensorB,SensorC)中,“observeValueForKeyPath:(NSString *)keyPath ofObject:(id)对象更改:(NSDictionary *)change context:(void *)context” 在我的观察者指南针没有被调用。我猜测它与反射有关,也许与这种技术的相关限制有关。或者可能是因为

unknown_cls = [[NSClassFromString(super.CompassName) alloc]init];
反映而不是
unknown_cls = [[NSClassFromString(super.CompassName) alloc]initWithLineToParse:array];

如何让这个为我工作? 可能是这样的错误尝试吗?谢谢你的帮助。

1 个答案:

答案 0 :(得分:2)

我认为这里的问题是你正在尝试使用Class作为实例。

你有

Class unknown_cls

并且您确实需要将未知类的实例用作KVO注册的目标。

id compass = [[NSClassFromString(CompassName) alloc] init];

现在您可以使用'compass'变量来注册KVO观察者。


只是为了澄清我对你的课程及其关系的理解:

AnalogCompass是一个充当一个或多个Sensor的观察者的类。当创建AnalogCompass的实例时,它应该将自己注册为名为Sensor类的观察者。

Sensor类声明了一个可以观察到的属性:depthInFeet

如果这是您的两个类的准确表示,您的代码将永远不会工作。您的AnalogCompass实例没有引用它应该观察的Sensor实例。您还试图观察一个从未被声明为Sensor的可观察属性的属性(xposition)。

我假设您的应用程序中至少有一个AnalogCompass实例和一个Sensor实例。 AnalogCompass实例应该观察Sensor实例的变化。

要使用KVO进行此项工作,您需要尽可能少地执行以下操作:

AnalogCompass *someCompass = ...;
Sensor *someSensor = ...;

/* Register someCompass as an observer of the 'xposition' 
property of someSensor */

[someSensor addObserver:someCompass forKeyPath:@"xposition" 
                options:0 context:NULL];

您还必须声明Sensor类具有名为'xposition'的可观察属性。

 @interface Sensor : NSObject
 @property (nonatomic, assign) float xposition;
 @end

 @implementation Sensor
 @synthesize xposition;
 @end

如果你想在AnalogCompass的初始值设定器中进行KVO设置,正如你的代码似乎在上面做的那样,你需要这样的东西:

@interface AnalogCompass : NSObject
{
    Sensor *sensor;
}
@end


@implementation AnalogCompass

- (id) initWithSensor:(Sensor *)aSensor 
{
    self = [super init];
    if (!self) return nil;

    sensor = [aSensor retain];

    [sensor addObserver:self forKeyPath:@"xposition" 
                options:0 context:NULL];

    return self;
}

- (void) dealloc
{
    [sensor removeObserver:self forKeyPath:@"xposition"];
    [sensor release];
    [super dealloc];
}

- (void) observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object 
                         change:(NSDictionary *)change context:(void *)context
{
    if ([keyPath isEqualToString:@"xposition"])
    {
      // Do something interesting with the value.
    }

    else
    {
      /* super gets to handle it */
      [super observeValueForKeyPath:keyPath ofObject:object 
                          change:change context:context];
    }
}
@end

如果您要使用多种Sensor类,那么您需要声明一个具有您想要观察的属性的公共子类(例如Sensor)(例如xposition)。您可以替代地定义所有Sensor类实现的@protocol,这反过来又定义了您要观察的属性。

我认为你可以避免使用反射/内省。您的应用程序将在运行时生成一组传感器和一些Compass对象。应用程序中的某些内容将跟踪它们(例如,某些其他对象或应用程序委托正在维护NSArray或NSSet传感器和/或指南针。

也许您的Compass类将在其初始化程序中创建自己的内部Sensor对象?从您的代码中发现的情况并不完全清楚。但是,在某些时候,您需要一个Compass对象和一个Sensor对象才能在它们之间注册KVO。