Swift - class method which must be overridden by s

2019-01-16 18:00发布

问题:

Is there a standard way to make a "pure virtual function" in Swift, ie. one that must be overridden by every subclass, and which, if it is not, causes a compile time error?

回答1:

You have two options:

1. Use a Protocol

Define the superclass as a Protocol instead of a Class

Pro: Compile time check for if each "subclass" (not an actual subclass) implements the required method(s)

Con: The "superclass" (protocol) cannot implement methods or properties

2. Assert in the super version of the method

Example:

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

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

Pro: Can implement methods and properties in superclass

Con: No compile time check



回答2:

There isn't any support for abstract class/ virtual functions, but you could probably use a protocol for most cases:

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'


回答3:

Another workaround, if you don't have too many "virtual" methods, is to have the subclass pass the "implementations" into the base class constructor as function objects:

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:

The following allows to inherit from a class and also to have the protocol's compile time check :)

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

}


回答5:

Being new to iOS development, I'm not entirely sure when this was implemented, but one way to get the best of both worlds is to implement an extension for a protocol:

protocol ThingsToDo {
    func doThingOne()
}

extension ThingsToDo {
    func doThingTwo() { /* Define code here */}
}

class Person: ThingsToDo {
    func doThingOne() {
        // Already defined in extension
        doThingTwo()
        // Rest of code
    }
}

The extension is what allows you to have the default value for a function while the function in the regular protocol still provides a compile time error if not defined