2

如果我执行以下操作,编译器不会抱怨:

id foo;
[foo retain];

但是,如果我执行以下操作,编译器会抱怨:

id<NSCopying> bar;
[bar retain];

具体来说,它说:

Instance method '-retain' not found (return type defaults to 'id')

为什么是这样?我认为 anid指向一个通用的 Objective-C 对象,并且我可以传递retain给任何 Objective-C 对象。

请注意,这是一个警告,而不是错误,所以我仍然可以编译代码并且它似乎可以工作。我还注意到我可以执行以下操作来抑制警告:

[(id)bar retain];

但我认为id<NSCopying>是 的一个子类型id,所以任何可以在 anid上完成的事情都可以在id <NSCopying>...

4

1 回答 1

2

您不一定可以发送retain任何Objective-C 对象。retain是 NSObject 协议的一部分。碰巧所有的 Cocoa 都符合 NSObject,但从语言的角度来看,它仍然不是真正的通用(可以定义一个不符合 NSObject 的类或从 NSObject 类继承;它只是不是很有用)。

将某事声明为id<NSCopying>意味着“只允许我在 NSCopying 协议中发送消息”——而 NSCopying 不包括retain. 为了从 NSObject 协议发送消息,您必须将变量声明为id(在这种情况下不会发生类型检查),id<NSObject>(在这种情况下您只能在 NSObject 协议中发送消息)或作为一个类的实例符合 NSObject。

在您将某些东西声明为 的情况下id<NSCopying>,您通常希望发送对象copy而不是retain,因为这就是以这种方式声明它的全部意义所在。如果 NSCopying 在这里代表你自己的协议,你可以通过像这样定义它来使协议本身符合 NSObject:

@protocol YourProtocol <NSObject>

如果你真的需要声明一个符合两个协议的变量(这很不寻常,但有时会出现),你可以用逗号分隔的协议列表来声明它,比如id<NSCopying,NSObject>.

于 2013-09-13T20:10:30.350 回答