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

时间:2014-06-08 22:07:37

标签: swift abstract swift-protocols

是否有标准的方法来制作一个纯粹的虚拟功能"在斯威夫特,即。一个必须被每个子类覆盖,如果不是,会导致编译时错误?

9 个答案:

答案 0 :(得分:126)

您有两种选择:

1。使用协议

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

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

Con :“超类”(协议)无法实现方法或属性

2。断言方法的超级版本

示例:

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

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

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

Con :无编译时检查

答案 1 :(得分:36)

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

protocol SomeProtocol {
    func someMethod()
}

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

如果SomeClass没有实现someMethod,那么你将得到这个编译时错误:

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

答案 2 :(得分:21)

以下内容允许从类继承,并允许检查协议的编译时间:)

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

}

答案 3 :(得分:14)

另一种解决方法,如果你没有太多"虚拟"方法,是让子类传递"实现"作为函数对象进入基类构造函数:

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

答案 4 :(得分:2)

您可以按照drewag的答案here中的建议使用协议与声明。 但是,缺少该协议的示例。我在这里报道,

协议

protocol SomeProtocol {
    func someMethod()
}

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

现在,需要每个子类来实现在编译时检查的协议。如果SomeClass没有实现someMethod,则会出现此编译时错误:

错误:类型“ SomeClass”不符合协议“ SomeProtocol”

注意:这仅适用于实现协议的最高级类。任何子类都可以巧妙地忽略协议要求。 –由memmons的{​​{3}}

断言

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

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

但是,断言仅在运行时有效。

答案 5 :(得分:1)

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

class SuperClass {}

protocol SuperClassProtocol {
    func someFunc()
}

typealias SuperClassType = SuperClass & SuperClassProtocol


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

答案 6 :(得分:0)

您可以通过将函数传递给初始化程序来实现。

例如

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
  • 的类

答案 7 :(得分:0)

我也想要这个编译时检查。我没有彻底研究提出的解决方案,但我认为协议解决方案行不通,因为继承的方法满足协议要求。

答案 8 :(得分:-1)

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

使用扩展名可以使函数具有默认值,而常规协议中的函数仍会提供编译时错误(如果未定义)