KVO с неизвестным наблюдаемым объектом до выполнения

У меня есть класс «Компас», который предназначен для наблюдения за другим классом «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

When I´m doing a change like self.xposition = position; in any of my observed and reflected Sensor Classes (SensorA,SensorB,SensorC), the "observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context" in my observer Compass ist not called. Im guessing it has something to do with the reflection and maybe with related restrictions of this kind of technique. Or maybe because reflecting with

unknown_cls = [[NSClassFromString(super.CompassName) alloc]init];
and not with
unknown_cls = [[NSClassFromString(super.CompassName) alloc]initWithLineToParse:array];

Как заставить это работать для меня? Может быть, это неправильная попытка такого наблюдения? Спасибо за помощь.


person Fabian Steinhauer    schedule 02.04.2011    source источник
comment
Похоже, проблема действительно в отражении, потому что я не могу вызывать в нем какие-либо функции. Что я могу сделать, чтобы получить свой экземпляр динамически?   -  person Fabian Steinhauer    schedule 03.04.2011
comment
Могу ли я вызывать статические методы только из отраженных экземпляров класса?   -  person Fabian Steinhauer    schedule 03.04.2011
comment
Вы увидите проблемы с памятью с переменными экземпляра showAnalog и showDigital. Вы используете простое присваивание для захвата значений аргументов, и этого недостаточно. Вам необходимо сохранить или скопировать значения аргументов, чтобы правильно управлять памятью переменных экземпляра. Что-то вроде showAnalog = [ShowAnalog copy];   -  person Bill Garrison    schedule 03.04.2011


Ответы (1)


Я думаю, проблема в том, что вы пытаетесь использовать класс в качестве экземпляра.

У вас есть

Class unknown_cls

и вам действительно нужен экземпляр неизвестного класса для использования в качестве цели для регистраций KVO.

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

Теперь вы можете использовать переменную compass для регистрации наблюдателей KVO.


Просто чтобы прояснить мое понимание ваших классов и их отношений:

AnalogCompass - это класс, который действует как наблюдатель одного или нескольких Sensor. Когда создается экземпляр AnalogCompass, он должен зарегистрироваться как наблюдатель namedSensorclass.

TheSensorclass декларирует одно свойство, которое можно наблюдать: depthInFeet

Если это точное представление двух ваших классов, ваш код никогда не будет работать. Ваш экземпляр AnalogCompass не получает ссылок на экземпляры Sensor, которые он должен наблюдать. Вы также пытаетесь наблюдать свойство (xposition), которое никогда не было объявлено как наблюдаемое свойство Sensor.

Я предполагаю, что в вашем приложении есть хотя бы один экземпляр 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

Если вы хотите выполнить настройку KVO в инициализаторе AnalogCompass, как ваш код, похоже, делает выше, вам нужно что-то вроде этого:

@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). В качестве альтернативы вы можете определить @protocol, который реализуют все классы Sensor, который, в свою очередь, определяет свойство, которое вы хотите наблюдать.

Я думаю, вы можете избежать использования рефлексии / самоанализа. Ваше приложение будет иметь набор датчиков и некоторое количество объектов Compass, работающих во время выполнения. Что-то в вашем приложении будет их отслеживать (например, какой-то другой объект или делегат приложения поддерживает NSArray или NSSet датчиков и / или компасов.

Может быть, ваш класс Compass собирается создать свой собственный внутренний объект Sensor в своем инициализаторе? Из вашего кода не совсем понятно, что происходит. Однако в какой-то момент вам понадобится один объект Compass и один объект Sensor, чтобы зарегистрировать KVO между ними.

person Bill Garrison    schedule 03.04.2011
comment
Спасибо за ответ, но, похоже, нет никакой разницы, использую ли я id. - person Fabian Steinhauer; 03.04.2011
comment
Большое спасибо за очень подробный комментарий, Билл. Я попробовал сделать это по-другому, без размышлений, но пока не справился. Ваш анализ помогает мне во многом. Подробнее напишу позже. - person Fabian Steinhauer; 04.04.2011