我有一个“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];
如何让这个为我工作? 可能是这样的错误尝试吗?谢谢你的帮助。
答案 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。