0

我最近一直在学习如何在 Objective-C 中使用协议(使用 Apple 的官方指南),我一直无法理解在我看来不一致的地方。在文档中指出 -

通过在属性上指定所需的协议一致性,如果您尝试将属性设置为不符合协议的对象,即使基本属性类类型是通用的,也会收到编译器警告。

所以我通过创建一个名为“XYZFakeProtocol”的协议和一个不符合该协议的名为“XYZPerson”的类来测试这一点。然后我尝试初始化一个泛型类变量,该变量预计符合 XYZFakeProtocol 如下 -

id <XYZFakeProtocol> speakingPerson = [[XYZPerson alloc] init];

正如预期的那样,XCode 标记了错误 -

<使用不兼容类型“XYZPerson *”的表达式初始化“__strong id XYZFakeProtocol>”

但是,当我做同样的事情而是使用工厂方法而不是手动分配和初始化实例时,不会出现错误。我使用的代码,工厂方法是 'person:' -

id <XYZFakeProtocol> speakingPerson = [XYZPerson person];

没有错误被标记,特别是有问题的是,当我调用协议中指定的方法时,也不会出现编译器错误,即使该方法实际上不在不符合标准的类中 - 这会导致我的程序崩溃。

那么这是 Xcode 的问题,还是使用工厂方法的预期和正确结果,如果是,是否可以向我解释这背后的原因,以便我了解如何最好地避免它编写一个真正的应用程序?

作为参考,如果我创建 XYZPerson 对象并将其分配给 XYZPerson 变量,然后将该变量分配给泛型类型变量,则 Xcode 会正确标记该类不符合协议的错误,而不管实例是否是使用创建的工厂方法或手动初始化 -

XYZPerson *helloPerson = [XYZPerson person];
XYZPerson *helloPerson2 = [[XYZPerson alloc] init];
id <XYZFakeProtocol> speakingPerson = helloPerson;
speakingPerson = helloPerson2;

谢谢。

4

2 回答 2

0

这取决于您的 XYZPerson 类是如何定义的。如果person返回id,则类型检查器会将其视为与任何对象类型兼容。如果person返回instancetype,您将收到有关协议一致性的错误。

于 2014-06-11T21:52:43.853 回答
0

可以安全地假设您已声明为:

+ (id)person;

将其更改为:

+ (instancetype)person;

id表示任何类型,因此编译器不知道返回的对象是否会实现协议。instancetype表示该类型的实例,因此编译器确实知道。

instancetype是一个相对较新的添加,因此编译器很乐意将它用于init方法。但是,对于工厂方法,它不愿意这样做。

于 2014-06-11T21:52:58.247 回答