【问题标题】:KVC on id type conforming to a protocol符合协议的 id 类型的 KVC
【发布时间】:2014-09-18 18:34:32
【问题描述】:

我偶然发现了 Xcode 6 中键值编码的问题。似乎不可能在符合协议的 id 上使用键值编码。

当一个属性被声明为 id 时编译器同意

@property (nonatomic, strong) id foo;

[foo setValue:@"value" forKey:@"key"];

当我将 id 设置为符合协议时,我得到一个编译器错误。 “没有已知的选择器实例方法...”。

@property (nonatomic, strong) id<MyProtocol> foo;

[foo setValue:@"value" forKey:@"key"];

如果我将类型设置为 NSObject,它会起作用,如下所示:

@property (nonatomic, strong) NSObject<MyProtocol> *foo;

[foo setValue:@"value" forKey:@"key"];

“MyProtocol”协议符合 NSObject,但据我了解,该对象必须是 NSObject 的子类才能使 KVC 工作。但为什么第一种情况有效,而第二种情况无效?

【问题讨论】:

  • 这与KVC没有任何关系; id s = @"WATERMELONS"; [s lowercaseString]; id &lt;MyProtocol&gt; r = s; [r lowercaseString]; 的结果相同。
  • 好吧,猜猜是有道理的。所以你不再被允许向符合协议的 id 发送任何消息?
  • id 是免费的;编译器只知道这个东西是一个 ObjC 对象。当你指定一个协议时,你已经稍微限制了类型——你基本上是在说“我不在乎这到底是什么,只要它有来自 MyProtocol 的方法”——但看起来编译器需要尽可能地限制。 只有 来自该协议的方法才能编译。不过,我不知道为什么;类型论中可能有原因。
  • 但这是 Xcode 6 中的新功能?

标签: objective-c kvc


【解决方案1】:

这在 Xcode 6 中并不新鲜。(我刚刚测试了 Xcode 5.1.1 并得到了一个错误。)规则是:

  • 编译器将允许您将任何消息发送到裸id

  • 如果消息由指定协议之一定义,编译器将只允许您向 id&lt;Protocol1, Protocol2, Protocol3, ...&gt; 发送消息。

  • 如果消息由指定协议之一定义,由类定义,编译器将只允许您向SomeClass&lt;Protocol1, Protocol2, Protocol3, ...&gt; 发送消息。类定义的消息包括其超类及其类别定义的消息。

setValue:forKey: 方法在NSKeyValueCoding category 中定义在NSObject class 上。 NSObject protocol 上没有定义。

【讨论】:

  • 对于这种协议类型检查的限制性,您能想到什么特别的原因吗?
  • 我想这是为了帮助您避免错误。如果您知道自己在做什么,则很容易转换为 id,但如果 IDE 认为每条消息都是有效的,则很难从 IDE 获得指导。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-12-09
  • 2019-11-23
  • 2014-05-12
  • 1970-01-01
  • 2023-03-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多