web-dev-qa-db-fra.com

Swift - méthode de classe qui doit être remplacée par la sous-classe

Existe-t-il un moyen standard de créer une "fonction virtuelle pure" dans Swift, c.-à-d. une qui doit doit être remplacée par chaque sous-classe et qui, si ce n’est pas le cas, provoque une erreur de compilation?

75
JuJoDi

Vous avez deux options:

1. Utiliser un protocole

Définir la superclasse en tant que protocole au lieu d'une classe

Pro : Vérification du temps de compilation pour savoir si chaque "sous-classe" (et non une sous-classe réelle) implémente les méthodes requises

Con : La "superclasse" (protocole) ne peut pas implémenter de méthodes ou de propriétés

2. Assert dans la super version de la méthode

Exemple:

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

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

Pro : Peut implémenter des méthodes et des propriétés dans la superclasse

Con : Pas de vérification du temps de compilation

118
drewag

Il n'y a pas de support pour les classes abstraites/fonctions virtuelles, mais vous pourriez probablement utiliser un protocole dans la plupart des cas:

protocol SomeProtocol {
    func someMethod()
}

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

Si SomeClass n'implémente pas someMethod, vous obtiendrez cette erreur de compilation:

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

Ce qui suit permet d’hériter d’une classe et aussi de vérifier le temps de compilation du protocole :)

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

}
15
JMiguel

Une autre solution, si vous n'avez pas trop de méthodes "virtuelles", consiste à faire en sorte que la sous-classe transmette les "implémentations" au constructeur de la classe de base en tant qu'objets fonction:

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)
    }
}
14
David Moles

En tant que nouveau dans le développement iOS, je ne suis pas tout à fait sûr de savoir quand cela a été implémenté, mais un moyen d'obtenir le meilleur des deux mondes consiste à implémenter une extension pour un protocole:

protocol ThingsToDo {
    func doThingOne()
}

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

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

L'extension est ce qui vous permet d'avoir la valeur par défaut pour une fonction alors que la fonction dans le protocole standard fournit toujours une erreur de temps de compilation si elle n'est pas définie

0
Jordan