首页 文章

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

提问于
浏览
0

我有一个“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 *)更改上下文:(void *)context”在我的观察者中指南针不被调用 . 我猜测它与反射有关,也许与这种技术的相关限制有关 . 或者也许是因为反思

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

而不是

unknown_cls = [[NSClassFromString(super.CompassName) alloc]initWithLineToParse:array];

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

1 回答

  • 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 .

相关问题