В Objective-C, учитывая идентификатор, как я могу сказать, на какой тип объекта он указывает?


цель-C вопрос новичка. Учитывая следующий (вымышленный) код:

id mysteryObject = [anotherObject mysteriousMethod];

Как я могу определить во время выполнения, что класс mysteryObject - это?

4 62

4 ответа:

[mysteryObject class]

получит вам объект класса. Однако, как правило, вы хотите сделать что-то Оопы, как проверить на соответствие некоторым протокола или интерфейса.

можно использовать isKindOfClass или isMemberOfClass

например:

if ([foo isMemberOfClass:[NSBar class]])

в динамически типизированном языке, таком как Objective-C (или Python или Ruby), вы часто не хочу чтобы узнать, что это за объект. Часто более продуктивно думать о том, отвечает ли объект на сообщение, которое вы хотите отправить; если это так, вам не нужно беспокоиться о том, какой класс он создает, и если это не так, вы должны обрабатывать случай независимо от типа экземпляра. Это известно как"утка набрав"...если он крякает, как утка, то это утка.

вы можете проверить отвечает ли объект на определенное сообщение (известное как селектор в Objective-C) следующим образом:

if([mysteryInstance respondsToSelector:@selector(messageIWishToSend)]) {
  [mysteryInstance messageIWishToSend];
} else {
  //handle case where instance doesn't respond to the desired message
}

даже лучше, чем тестирование для отдельных селекторов, чтобы определить @protocol это описывает API, который вы хотите использовать для своих классов:

// MyProtocol.h
@protocol MyProtocol
- (void)methodInMyProtocol;
@end

//MyClass.h

#import "MyProtocol.h"

@interface MyClass <MyProtocol> {

}
- (void)methodInMyProtocol;
@end

вы можете проверить, реализует ли экземпляр MyProtocol протокол такой:

if([mysteryInstance conformsToProtocol:@protocol(MyProtocol)]) {
  [mysteryInstance methodInMyProtocol];
} else {
  // ...
}

этот способ делать вещи часто неудобно для людей, приходящих из статически типизированных языков, таких как Java или C++. Вы теряете типы проверки компилятора для вас. Однако динамическая типизация упрощает многие вещи, в том числе тестирование, поскольку вы можете легко заменить экземпляр поддельным во время тестирования. Таким образом, динамический подход к языку заключается в том, чтобы больше тестировать и меньше беспокоиться о типах. У вас есть хорошее покрытие модульных тестов, не так ли?

если вы действительно должны определить класс экземпляра во время выполнения (и вы действительно, вероятно, не нужно), вы можете использовать -[NSObject isKindOfClass:] чтобы проверить правильность экземпляр-это экземпляр класса или любого из его подклассов или -[NSObject isMemberOfClass:] чтобы проверить, является ли экземпляр является экземпляром определенного класса. Вы можете проверить Class объект непосредственно как возвращение -[NSObject class] и вы можете получить строковое имя класса экземпляра с NSStringFromClass([mysteryInstance class]).

я обнаружил, что мне пришлось вернуться к id при использовании метода, определенного в протоколе@.

например, self.слушатели-это массив id

Если я это сделаю ....

for(id<PropertyListener> listener in self.listeners) {        
    if ( [ [ listener class]  respondsToSelector:@selector(propertyChanged:propertyName:)]) {

Я получаю сообщение об ошибке "нет известного метода экземпляра для селектора 'class'". Тем не менее, когда я бросаю идентификатор от идентификатора к идентификатору, он работает ... Почему-не понимаю.

[ ((id)listener) class] respondsToSelector .... 

вот полный цикл ...

for(id<PropertyListener> listener in self.listeners) {        
    if ( [ [ ((id)listener) class]  respondsToSelector:@selector(propertyChanged:propertyName:)]) {
        [listener propertyChanged: self propertyName:@"thePropName"];
    } else {
        [listener propertyChanged: self];
    }
}