声明变量“id”和“NSObject *”之间有什么区别?

时间:2009-01-21 20:12:53

标签: objective-c

在Objective-C中,声明变量id与声明NSObject *之间的区别是什么?

4 个答案:

答案 0 :(得分:51)

使用变量类型id,您可以发送任何已知消息,编译器不会抱怨。使用变量类型NSObject *,您只能向它发送由NSObject声明的消息(不是任何子类的方法),否则它将生成警告。一般来说,id就是你想要的。

进一步说明:所有对象基本上都是id类型。声明静态类型的要点是告诉编译器“假设此对象是此类的成员”。因此,如果你发送一个类没有声明的消息,编译器可以告诉你,“等等,那个对象不应该得到那个消息!”此外,如果两个类具有相同名称但签名不同的方法(即参数或返回类型),则可以猜出您为变量声明的类所指的方法。如果它被声明为id,编译器就会举起手来告诉你,“好的,我这里没有足够的信息。我随机选择方法签名。” (但这通常不会通过声明NSObject*来帮助。通常冲突是在两个更具体的类之间。)

答案 1 :(得分:17)

id表示“对象”,NSObject *表示“NSObject或其子类之一”。 Objective-C中的对象不是NSObject s(目前你在Cocoa中遇到的对象是NSProxyProtocolClass)。如果某些代码需要特定类的对象,则声明这有助于编译器检查您是否正确使用它。如果您真的可以使用“任何对象” - 例如,您正在声明代理并将使用respondsToSelector:调用测试所有方法发送 - 您可以使用id

声明对象变量的另一种方法是“id <NSObject>”,这意味着“任何实现NSObject协议的对象。

答案 2 :(得分:10)

根据我对Objective-C的有限理解,并非所有对象都是从NSObject派生的(与Java所有对象派生自Object的不同)。理论上你可以有其他的根对象。 id可以应用于任何非NSObject派生对象。

答案 3 :(得分:0)

我想补充另一个不同之处。当您向id添加协议时,它不再意味着它将是NSObject *类型,它只是意味着它将是确认该协议的任何类。

因此,例如,此代码不会引发任何错误,因为NSObject的类别NSDelayedPerforming具有该方法:

id testId;
[testId performSelector:@selector(isKindOfClass:) withObject:[NSObject class] afterDelay:.5];

但是,此代码将显示错误No known instance method for selector "performSelector:withObject:afterDelay:"

id<NSMutableCopying> testId;
[testId performSelector:@selector(isKindOfClass:) withObject:[NSObject class] afterDelay:.5];