Objective-C运行时:声明一个符合协议的Class(objc_class)类型的变量意味着什么?

8
Class bah = [NSString class];

id object = [bah new];

编译时无任何问题。

Class<NSSecureCoding> bah = [NSString class];

id object = [bah new];

返回错误信息"No known class method for selector 'new'"。
为什么第一个实例可以调用NSObject定义的+new方法,而第二个实例不能?涉及到技术细节,请参阅相关技术文档。
2个回答

5
根据苹果的文档:
协议不能用于类型化类对象。只有实例可以静态地类型化为协议,就像只有实例可以静态地类型化为类一样。(但是,在运行时,类和实例都会响应conformsToProtocol:消息。)
这是来自旧文档的内容,但没有任何说明它是否已经改变。但是,基于此,假设它仍然有效,则不应该执行您正在执行的操作。NSString的实例可能符合该协议,但不应说NSString Class对象符合该协议。
至于为什么会出现错误,我认为这是因为在指定协议时,它将报告不属于该协议的方法的错误。例如,以下代码会报错:
Class<NSSecureCoding> bah = [NSString class];
id object = [bah class];

但是以下代码可以编译通过(尽管会给出一个警告,提示class是一个实例方法而不是类方法):
Class<NSObject> bah = [NSString class];
id object = [bah class];

您会注意到在NSObject协议中未定义new,只有在NSObject类中定义了它。

因此,当您仅指定Class时,编译器似乎会执行与指定id类似的操作,即它不知道确切的类型,因此将允许您从任何已知类型调用方法。但是,当您向其添加协议时,它只允许您从该协议调用方法。

如果您想要确保分配给bah的任何内容符合特定协议而仅使用Class,则可以使用以下内容:

if ([bah conformsToProtocol:@protocol(NSSecureCoding)])

3
这是您所提到的遗留文档的链接:面向对象编程和Objective-C编程语言1.0,第62页。(我差不多写完了答案 :-)) - Martin R
1
@MartinR 感谢您提供文档链接。 - Gavin
2
顺便提一下,Class<AnyProcol> = [NSString class] 对于任何协议都可以编译而不会出现警告。- 参见http://lists.cs.uiuc.edu/pipermail/llvmbugs/2013-March/027464.html。 - Martin R
@MartinR 是的,但很多本不应该被做的事情仍然可以编译通过 :) - Gavin
干得好,伙计们。我在文档中搜索了一些关于这个问题的内容,但是没有找到。感谢你们的辛勤工作。 - Reid Main
哦,我只是随机选择了NSString作为要使用的类。我知道它不符合协议。我更感兴趣的是编译器为什么会抛出一个错误而另一个不会。我也可以轻松地将bah设置为nil并获得相同的结果。 - Reid Main

1

Class<NSSecureCoding>是一个对象,响应协议NSSecureCoding的类方法。协议NSSecureCoding没有声明方法+new,因此您无法调用它。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接