为什么我不能在协议中声明动态变量

Why can't I declare dynamic variable inside protocol

我目前正在为我的 object 开发协议,它继承自 Realm 的 Object。在我的 object 中我有变量,这些变量被标记为 @objc dynamic

@objc dynamic var title: String = ""

现在想象一下我有更多具有相同变量 title 的相似 object 的情况。我想为他们创建协议,因为我只想使用一种泛型方法来更改 object.

的标题

所以,我创建了带有 title 变量标记为 @objc dynamic 的协议,并期望它是这样工作的

protocol Titleable: class {
    @objc dynamic var title: String { get set }
}

...这没有成功,我实际上收到了两个错误。

关于将变量标记为 @objc

@objc can only be used with members of classes, @objc protocols, and concrete extensions of classes

...我可以通过将协议标记为 @objc 来解决这个问题。

但是我仍然遇到与 dynamic 关键字相关的错误

Only members of classes may be dynamic

...我认为当我为 classes 约束协议时,它应该没问题,但是...它不是。

我通过删除 @objc 以及 dynamic 关键字以某种方式解决了这个问题

protocol Titleable: class {
    var title: String { get set }
}

...行得通。我可以在实现此协议的 class 中将变量标记为 @objc dynamic

class Item: Object, Titleable {
    @objc dynamic var title: String = ""
}

但是,我不确定为什么这有效,为什么在协议声明中将变量标记为 dynamic 无效。我将不胜感激任何解释。

看看什么dynamic means:

dynamic

Apply this modifier to any member of a class that can be represented by Objective-C. When you mark a member declaration with the dynamic modifier, access to that member is always dynamically dispatched using the Objective-C runtime. Access to that member is never inlined or devirtualized by the compiler.

Because declarations marked with the dynamic modifier are dispatched using the Objective-C runtime, they must be marked with the objc attribute.

请特别注意第一段。它说标记为 dynamic 的东西不能被静态调度。现在考虑我在模块中有一些 class 的情况。它已经被编译,并且它的方法是静态调度的。现在考虑另一个模块,它使 class 符合某些包含 dynamic 方法的协议。这怎么行?该方法已 已经 在某些地方静态调度。它不能追溯转换为动态调度。 (这同样适用于同一模块中的声明,具体取决于编译器标志和访问级别,但我发现解释跨模块更容易。)

在任何情况下您想要这样做的主要原因是确保您可以在 属性 上使用 KVO。 (如果您有其他原因需要强制符合类型使用动态 属性,我很想知道用例。)如果这是您的目标,我可能会要求 Titleable符合NSObjectProtocol.