在Objective-C中,声明变量id
与声明NSObject *
之间的区别是什么?
答案 0 :(得分:51)
使用变量类型id
,您可以发送任何已知消息,编译器不会抱怨。使用变量类型NSObject *
,您只能向它发送由NSObject声明的消息(不是任何子类的方法),否则它将生成警告。一般来说,id
就是你想要的。
进一步说明:所有对象基本上都是id
类型。声明静态类型的要点是告诉编译器“假设此对象是此类的成员”。因此,如果你发送一个类没有声明的消息,编译器可以告诉你,“等等,那个对象不应该得到那个消息!”此外,如果两个类具有相同名称但签名不同的方法(即参数或返回类型),则可以猜出您为变量声明的类所指的方法。如果它被声明为id
,编译器就会举起手来告诉你,“好的,我这里没有足够的信息。我随机选择方法签名。” (但这通常不会通过声明NSObject*
来帮助。通常冲突是在两个更具体的类之间。)
答案 1 :(得分:17)
id
表示“对象”,NSObject *
表示“NSObject
或其子类之一”。 Objective-C中的对象不是NSObject
s(目前你在Cocoa中遇到的对象是NSProxy
,Protocol
和Class
)。如果某些代码需要特定类的对象,则声明这有助于编译器检查您是否正确使用它。如果您真的可以使用“任何对象” - 例如,您正在声明代理并将使用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];