Как типизировать id динамически в конкретный класс во время выполнения? - PullRequest
2 голосов
/ 22 мая 2009

У меня есть несколько источников данных, которые я использую для одного UIViewController. Мой контроллер представления использует KeyValue Observing для отслеживания состояния определенных свойств во время выполнения. Когда я меняю источники данных, мне нужно перестать наблюдать за этими свойствами. Проблема в том, что я не уверен в классе источника данных во время выполнения, поэтому что-то вроде этого недопустимо:

if (aDataSource != dataSource) {
    // Ensure we stop observing the existing dataSource, otherwise bad stuff can happen.
    [dataSource removeObserver:self forKeyPath:@"someKeyPath"]; // not valid, compiler doesn't know what class dataSource is.
    [dataSource release];
    dataSource = [aDataSource retain];
}

Компилятору нужен конкретный класс, чтобы знать интерфейс объекта. Как я могу получить класс dataSource в этом конкретном случае, а затем набрать dataSource для removeObserver: forKeyPath: селектор выше? Я предпочитаю что-то динамическое / умнее, чем кэшировать имя класса в экземпляре NSString и ссылаться на это всякий раз, когда я переключаюсь. То есть я всегда мог сделать что-то вроде:

NSString *lastDataSource = @"MyClass";
Class foo = [NSClassFromString(lastDataSource)];

Спасибо.

Ответы [ 4 ]

6 голосов
/ 22 мая 2009
  1. Если вы напишите так:

    id foo = ...;
    [foo removeObserver:self forKeyPath:@"someKeyPath"];
    

    Компилятор будет в порядке, поскольку объекты типа id принимают любое сообщение (если подпись известна компилятору).

  2. Теперь, если у вас есть:

    id<NSObject> foo = ...;
    [foo removeObserver:self forKeyPath:@"someKeyPath"];
    

    Компилятор выдаст вам предупреждение:

    предупреждение: '-removeObserver: forKeyPath:' не найден в протоколе

    Это потому, что вы ссылаетесь на NSObject протокола, а не на класс NSObject, в котором определены методы KVO.

  3. Но если у вас есть:

    NSObject* foo = ...;
    [foo removeObserver:self forKeyPath:@"someKeyPath"];
    

    Это тоже хорошо скомпилируется, так как в этом случае вы используете класс NSObject.

Ссылки по теме:

2 голосов
/ 22 мая 2009

Что значит недействительный? Вы получаете ошибку компиляции?

Objective-C по умолчанию поддерживает динамическую типизацию объектов. Вы должны иметь возможность вызывать любой метод любого объекта в Objective-C, даже если компилятор не может гарантировать от статического типа, что этот объект поддерживает этот метод.

1 голос
/ 24 мая 2009

Позвольте мне добавить, что подход, который вы изложили ...

NSString *lastDataSource = @"MyClass";
Class foo = [NSClassFromString(lastDataSource)];

... конечно, не сможет подавить ваши предупреждения во время компиляции, так как класс "foo" вычисляется только во время выполнения. Таким образом, хотя вы, как программист, можете ясно видеть из кода, что «foo» в конечном итоге станет классом «MyClass», это не ясно для компилятора, и поэтому, если «MyClass» имеет метод «myMethod:», вы будете по-прежнему получит предупреждение компилятора, если вы отправите это сообщение объекту, объявленному как "foo".

Полагаю, вы понимаете это, но лучше пояснить, почему такой подход не решит вашу проблему.

1 голос
/ 22 мая 2009

Я думаю, вам нужно привести их к NSObject *, так как именно здесь используются методы KVO (не в протоколе NSObject).

...