我倾向于只将必需品(存储属性、初始化器)放入我的类定义中,并将其他所有内容移动到它们自己的 extension
中,有点像每个逻辑块使用 // MARK:
进行分组的 extension
。
例如,对于 UIView 子类,我最终会得到一个用于布局相关内容的扩展,一个用于订阅和处理事件等等。在这些扩展中,我不可避免地要覆盖一些 UIKit 方法,例如 layoutSubviews
。我从来没有注意到这种方法有任何问题——直到今天。
以这个类层次结构为例:
public class C: NSObject {
public func method() { print("C") }
}
public class B: C {
}
extension B {
override public func method() { print("B") }
}
public class A: B {
}
extension A {
override public func method() { print("A") }
}
(A() as A).method()
(A() as B).method()
(A() as C).method()
输出是 A B C
。这对我来说没什么意义。我听说协议扩展被静态发送了,但这不是协议。这是一个常规类,我希望方法调用在运行时被动态分派。显然,对 C
的调用至少应该是动态调度的,并产生 C
?
如果我从 NSObject
中删除继承,并使 C
成为一个根类,编译器会报告说 declarations in extensions cannot override yet
,这个我已经读过了。但是 NSObject
作为根类是如何改变事情的呢?
移动这两个重写到他们的类声明产生 A A A
如预期,移动只有 B
的产生 A B B
,移动只有 A
的产生 C B C
,其中最后一个对我来说完全没有意义: 甚至不是一个静态类型的 A
产生 A
-输出了!
将 dynamic
关键字添加到定义中或者重写似乎给了我所期望的行为“从类层次结构的那一点向下”..。
让我们把我们的例子换成一些不那么结构化的东西,是什么让我发布了这个问题:
public class B: UIView {
}
extension B {
override public func layoutSubviews() { print("B") }
}
public class A: B {
}
extension A {
override public func layoutSubviews() { print("A") }
}
(A() as A).layoutSubviews()
(A() as B).layoutSubviews()
(A() as UIView).layoutSubviews()
我们现在得到 A B A
。在这里我不能使 UIView 的布局 Subviews 动态的任何手段。
移动两个重写到他们的类声明得到我们再次 A A A
,只有 A 的或只有 B 的仍然得到我们 A B A
。dynamic
再次解决了我的问题。
理论上我可以把 dynamic
加到我所做的所有 override
中,但是我觉得我在这里做错了一些事情。
像我一样使用 extension
对代码进行分组真的是错误的吗?