在Objective-C中,给定一个id,我该如何判断它指向的对象类型?

Jus*_*cle 65 objective-c

Objective-C新手问题.鉴于以下(虚构)代码:

id mysteryObject = [anotherObject mysteriousMethod];
Run Code Online (Sandbox Code Playgroud)

如何在运行时确定哪个类mysteryObject是什么?

Rol*_*ien 92

你可以使用isKindOfClassisMemberOfClass

例如:

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

  • `isKindOfClass`表示对象继承自类,`isMemberOfClass`表示完全相同的类 (18认同)
  • 为了更精确一点@bendytree,`isKindOfClass`意味着完全相同的类,同时也意味着对象继承自类 (3认同)

p00*_*0ya 83

[mysteryObject class]
Run Code Online (Sandbox Code Playgroud)

会得到你的班级对象.但是,通常你想做一些OOPy,比如检查一些协议或接口的一致性.


Bar*_*ark 52

在像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
}
Run Code Online (Sandbox Code Playgroud)

甚至比测试单个选择器更好的是定义一个@protocol描述您希望用于类的API:

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

//MyClass.h

#import "MyProtocol.h"

@interface MyClass <MyProtocol> {

}
- (void)methodInMyProtocol;
@end
Run Code Online (Sandbox Code Playgroud)

您可以测试实例是否实现如下MyProtocol协议:

if([mysteryInstance conformsToProtocol:@protocol(MyProtocol)]) {
  [mysteryInstance methodInMyProtocol];
} else {
  // ...
}
Run Code Online (Sandbox Code Playgroud)

对于来自Java或C++等静态类型语言的人来说,这种做事方式通常会让人感到不舒服.您松开了编译器检查类型.动态类型使得很多事情变得更容易,包括测试,因为您可以在测试时轻松地用假替换实例.因此,动态语言方法是测试更多并且更少担心类型.你确实有良好的单元测试覆盖率,不是吗?

如果您确实必须在运行时确定实例的类(并且您可能根本不需要),则可以使用它-[NSObject isKindOfClass:]来测试实例是类的实例还是其任何子类,或者-[NSObject isMemberOfClass:]测试实例是否是实例是特定类的实例.您可以Class直接检查对象作为返回,-[NSObject class]并且您可以获取实例类的字符串名称NSStringFromClass([mysteryInstance class]).