2009-05-22 2 views
2

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

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 в этом конкретном случае, а затем typcast dataSource для removeObserver: forKeyPath: селектор выше? Я предпочитаю что-то динамическое/умнее кэширования имени класса в экземпляре NSString и ссылаясь на это при каждом переключении. Смысл, я всегда мог бы сделать что-то вроде:

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

Спасибо.

ответ

6
  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

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

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

+0

Нет, даже если я согласую свой объект типа 'id' с номером , я получаю предупреждение: '-removeObserver: forKeyPath:' не найден в протоколах – 2009-05-22 17:54:33

+0

Комментарий newacct верен и не подходит, t downvote. предупреждение является безобидным, пока программист может быть уверен, что метод будет установлен во время выполнения. любить или ненавидеть, ObjC основан на концепции, известной как утиная печать. – harms

+0

Так что, если вы не ставите на него протокол? Просто «id». Что вы получаете? – newacct

1

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

1

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

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

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

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

Смежные вопросы