Подтвердить что ты не робот

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

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

id mysteryObject = [anotherObject mysteriousMethod];

Как определить во время выполнения класс mysteryObject?

4b9b3361

Ответ 1

[mysteryObject class]

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

Ответ 2

Вы можете использовать isKindOfClass или isMemberOfClass

Например:

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

Ответ 3

На динамически типизированном языке, таком как 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 или С++. Вы потеряете для себя типы проверки компилятора. Однако динамическая типизация упрощает многое, включая тестирование, поскольку вы можете легко заменить экземпляр фальшивкой во время тестирования. Таким образом, динамический языковой подход состоит в том, чтобы тестировать больше и беспокоиться о типах меньше. У вас действительно хороший охват unit test, не так ли?

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

Ответ 4

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

Например, self.listeners - это массив id

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

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

Я получаю сообщение об ошибке "Неизвестный метод экземпляра для класса select". Тем не менее, когда я отбрасываю id с id на id, это работает... Почему я не понимаю.

[ ((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];
    }
}