Swift-class 方法,必须由子类重写

在 Swift 中是否有一个标准的方法来创建一个“纯虚函数”,即。一个 必须的被每个子类覆盖,如果没有,会导致编译时错误?

63087 次浏览

对抽象类/虚函数没有任何支持,但是在大多数情况下,您可以使用协议:

protocol SomeProtocol {
func someMethod()
}


class SomeClass: SomeProtocol {
func someMethod() {}
}

If SomeClass doesn't implement someMethod, you'll get this compile time error:

error: type 'SomeClass' does not conform to protocol 'SomeProtocol'

你有两个选择:

1. 使用协议

将超类定义为协议而不是类

Pro : 编译时检查每个“子类”(不是实际的子类)是否实现了所需的方法

反对 : “超类”(protocol)不能实现方法或属性

2. 在方法的超级版本中断言

例如:

class SuperClass {
func someFunc() {
fatalError("Must Override")
}
}


class Subclass : SuperClass {
override func someFunc() {
}
}

Pro : 可以在超类中实现方法和属性

Con : 没有编译时检查

另一个解决方法,如果你没有太多的“虚”方法,是让子类把“实现”作为函数对象传递给基类构造函数:

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)
}
}

作为 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
}
}

扩展允许您拥有函数的默认值,而常规协议中的函数如果没有定义,仍然会提供编译时错误

下面允许从类继承,也允许检查协议的编译时间:)

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() { ... }


}

您可以使用协议与断言,正如在 drewag的答案 给你中所建议的那样。 但是,协议的例子不见了,我在这里说明,

规定

protocol SomeProtocol {
func someMethod()
}


class SomeClass: SomeProtocol {
func someMethod() {}
}

现在每个子类都需要实现在编译时检查的协议。如果 Some Class 没有实现 some Method,那么会得到这个编译时错误:

错误: 输入‘ Some Class’不符合协议‘ Some Protocol’

注意: 这只适用于实现协议的最顶层类。任何子类都可以轻松地忽略协议需求。作为 评论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 传递给函数,因此不会出现内存泄漏。

Con:

  • 这不是最漂亮的代码
  • You can't use it for the classes with required init

这是我经常做的,导致编译时错误:

class SuperClass {}


protocol SuperClassProtocol {
func someFunc()
}


typealias SuperClassType = SuperClass & SuperClassProtocol




class Subclass: SuperClassType {
func someFunc() {
// ...
}
}