是否有在 Swift 中创建“纯虚函数”的标准方法,即。一个必须被每个子类覆盖的,如果不是,会导致编译时错误?
8 回答
你有两个选择:
1. 使用协议
将超类定义为协议而不是类
Pro:编译时检查每个“子类”(不是实际的子类)是否实现了所需的方法
缺点:“超类”(协议)无法实现方法或属性
2.在方法的超级版本中断言
例子:
class SuperClass {
func someFunc() {
fatalError("Must Override")
}
}
class Subclass : SuperClass {
override func someFunc() {
}
}
Pro : 可以在超类中实现方法和属性
缺点:没有编译时检查
以下允许从类继承并检查协议的编译时间:)
protocol ViewControllerProtocol {
func setupViews()
func setupConstraints()
}
typealias ViewController = ViewControllerClass & ViewControllerProtocol
class ViewControllerClass : UIViewController {
override func viewDidLoad() {
self.setup()
}
func setup() {
guard let controller = self as? ViewController else {
return
}
controller.setupViews()
controller.setupConstraints()
}
//.... and implement methods related to UIViewController at will
}
class SubClass : ViewController {
//-- in case these aren't here... an error will be presented
func setupViews() { ... }
func setupConstraints() { ... }
}
对抽象类/虚函数没有任何支持,但在大多数情况下您可能会使用协议:
protocol SomeProtocol {
func someMethod()
}
class SomeClass: SomeProtocol {
func someMethod() {}
}
如果 SomeClass 没有实现 someMethod,你会得到这个编译时错误:
error: type 'SomeClass' does not conform to protocol 'SomeProtocol'
如果您没有太多“虚拟”方法,另一种解决方法是让子类将“实现”作为函数对象传递给基类构造函数:
class MyVirtual {
// 'Implementation' provided by subclass
let fooImpl: (() -> String)
// Delegates to 'implementation' provided by subclass
func foo() -> String {
return fooImpl()
}
init(fooImpl: (() -> String)) {
self.fooImpl = fooImpl
}
}
class MyImpl: MyVirtual {
// 'Implementation' for super.foo()
func myFoo() -> String {
return "I am foo"
}
init() {
// pass the 'implementation' to the superclass
super.init(myFoo)
}
}
这是我通常做的,导致编译时错误:
class SuperClass {}
protocol SuperClassProtocol {
func someFunc()
}
typealias SuperClassType = SuperClass & SuperClassProtocol
class Subclass: SuperClassType {
func someFunc() {
// ...
}
}
您可以按照此处的回答中的建议使用协议与断言drewag
。但是,缺少该协议的示例。我在这里覆盖,
协议
protocol SomeProtocol {
func someMethod()
}
class SomeClass: SomeProtocol {
func someMethod() {}
}
现在每个子类都需要实现在编译时检查的协议。如果 SomeClass 没有实现 someMethod,你会得到这个编译时错误:
错误:类型“SomeClass”不符合协议“SomeProtocol”
注意:这仅适用于实现协议的最顶层类。任何子类都可以愉快地忽略协议要求。–正如评论memmons
断言
class SuperClass {
func someFunc() {
fatalError("Must Override")
}
}
class Subclass : SuperClass {
override func someFunc() {
}
}
但是,断言仅在运行时有效。
您可以通过将函数传递给初始化程序来实现它。
例如
open class SuperClass {
private let abstractFunction: () -> Void
public init(abstractFunction: @escaping () -> Void) {
self.abstractFunction = abstractFunction
}
public func foo() {
// ...
abstractFunction()
}
}
public class SubClass: SuperClass {
public init() {
super.init(
abstractFunction: {
print("my implementation")
}
)
}
}
您可以通过传递 self 作为参数来扩展它:
open class SuperClass {
private let abstractFunction: (SuperClass) -> Void
public init(abstractFunction: @escaping (SuperClass) -> Void) {
self.abstractFunction = abstractFunction
}
public func foo() {
// ...
abstractFunction(self)
}
}
public class SubClass: SuperClass {
public init() {
super.init(
abstractFunction: {
(_self: SuperClass) in
let _self: SubClass = _self as! SubClass
print("my implementation")
}
)
}
}
亲:
- 编译时检查每个子类是否实现了所需的方法
- 可以在超类中实现方法和属性
- 请注意,您不能将 self 传递给该函数,因此不会发生内存泄漏。
缺点:
- 这不是最漂亮的代码
- 你不能用它来上课
required init
作为 iOS 开发的新手,我不完全确定何时实现,但获得两全其美的一种方法是实现协议的扩展:
protocol ThingsToDo {
func doThingOne()
}
extension ThingsToDo {
func doThingTwo() { /* Define code here */}
}
class Person: ThingsToDo {
func doThingOne() {
// Already defined in extension
doThingTwo()
// Rest of code
}
}
扩展允许您拥有函数的默认值,而常规协议中的函数如果未定义仍会提供编译时错误