在 Objective-C 中,给定一个 id,我怎么知道它指向什么类型的对象?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1123485/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 21:54:30  来源:igfitidea点击:

In Objective-C, given an id, how can I tell what type of object it points to?

objective-c

提问by Justicle

Objective-C newbie question. Given the following (fictional) code:

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

id mysteryObject = [anotherObject mysteriousMethod];

How can I determine at runtime what class mysteryObjectis?

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

回答by Roland Rabien

You can use isKindOfClassor isMemberOfClass

您可以使用isKindOfClassisMemberOfClass

For example:

例如:

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

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

回答by p00ya

[mysteryObject class]

will get you the class object. However, generally you want to do something OOPy like check for conformance to some protocol or interface.

会给你类对象。但是,通常您想要做一些 OOPy 的事情,比如检查对某些协议或接口的一致性。

回答by Barry Wark

In a dynamically typed language like Objective-C (or Python or Ruby), you often don't wantto know what type of object it is. It's often more productive to think of whether the object responds to the message you wish to send; if it does, you shouldn't care what class it instantiates and if it doesn't you must handle the case regardless of the instance's type. This is known as "duck typing"...if it quacks like a duck it is a duck.

在像 Objective-C(或 Python 或 Ruby)这样的动态类型语言中,您通常不想知道它是什么类型的对象。考虑对象是否响应您希望发送的消息通常会更有成效;如果是这样,您不应该关心它实例化的类,如果不是,则无论实例的类型如何,您都必须处理这种情况。这被称为“鸭子打字”……如果它像鸭子一样嘎嘎叫,那就是鸭子。

You can test whether an object responds to a particular message (known as a selector in Objective-C) like this:

您可以像这样测试对象是否响应特定消息(在 Objective-C 中称为选择器):

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

Even better than testing for individual selectors is to define a @protocolthat describes the API you wish to use for your classes:

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

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

//MyClass.h

#import "MyProtocol.h"

@interface MyClass <MyProtocol> {

}
- (void)methodInMyProtocol;
@end

You can test whether an instance implements the MyProtocolprotocol like this:

你可以测试一个实例是否实现了MyProtocol这样的协议:

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

This way of doing things is often uncomfortable for folks coming from statically typed languages like Java or C++. You loose the compiler checking types for you. Dynamic typing makes a great many things easier however, including testing since you can easily replace an instance with a fake at test time. Thus the dynamic language approach is to test more and worry about types less. You do have good unit test coverage, don't you?

对于使用静态类型语言(如 Java 或 C++)的人来说,这种做事方式通常很不舒服。您为您松散了编译器检查类型。然而,动态类型使许多事情变得更容易,包括测试,因为您可以在测试时轻松地用伪造的实例替换实例。因此,动态语言方法是多测试,少担心类型。你确实有很好的单元测试覆盖率,不是吗?

If you really must determine the class of an instance at run time (and you really probably don't need to), you can use -[NSObject isKindOfClass:]to test whether an instance is an instance of a class or any of its subclasses or -[NSObject isMemberOfClass:]to test whether an instance is an instance of a particular class. You can inspect the Classobject directly as the return of -[NSObject class]and you can get the string name of the instance's class with NSStringFromClass([mysteryInstance class]).

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

回答by Bryan

I found I had to cast back to id when used with a method defined in a @protocol.

我发现当与@protocol 中定义的方法一起使用时,我必须转换回 id。

For example, self.listeners is an array of id

例如,self.listeners 是一个 id 数组

If I do this ....

如果我这样做......

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

I get an error "No known instance method for selector 'class'". Yet, when I cast the id from id to id it works ... Why I do not understand.

我收到错误消息“选择器‘类’没有已知的实例方法”。然而,当我将 id 从 id 转换为 id 时它会起作用......为什么我不明白。

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

Here is the full loop ...

这是完整的循环......

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