J'essaie d'implémenter du code orienté objet en utilisant un protocole générique. Disons que j'ai deux protocoles
protocol Executable: class {
func execute()
}
protocol Dockable: class {
associatedtype T
func dock(object: T)
}
J'ai mis en place un décorateur pour l'exécutable:
final class DockableExecutable: Executable, Dockable {
typealias T = Executable
private let decorated: Executable
private var docked: Executable?
init(_ decorated: Executable) {
self.decorated = decorated
}
// from Executable
func execute() {
decorated.execute()
docked?.execute()
}
// from Dockable
func dock(object: Executable) {
docked = object
}
}
Maintenant, je ne veux pas l'utiliser dans un cours comme celui-ci:
final class MyViewController: UIViewController {
init(save: Executable, uiUpdateConnector: Dockable<Executable>) {}
}
Mais ce n'est pas possible car le protocole lui-même n'est pas générique, seulement la fonction. Le compilateur me dit:
Impossible de spécialiser le type non générique 'Dockable'
L'idée est de l'utiliser comme ça:
let dockableExecutable = DockableExecutable(
SQLUpdateExecutable(/** dependencies **/)
)
let controller = MyViewController(save: dockableExecutable, uiUpdateConnector: dockableExecutable)
Comment la syntaxe correcte dans Swift 3 rend-elle le compilateur heureux?
MISE À JOUR 1
J'ai fait des progrès avec le code suivant:
final class MyViewController: UIViewController {
init<DOCKABLE: Dockable>(save: Executable, uiUpdateConnector: DOCKABLE) where DOCKABLE.T: Executable {}
}
Cela semble étrange, peut-être que quelqu'un a une meilleure idée? En utilisant la classe maintenant, je reçois:
Le paramètre générique 'DOCKABLE' n'a pas pu être déduit
Donc, mes questions n'ont pas changé:
Comment la syntaxe correcte dans Swift 3 rend-elle le compilateur heureux?
Mise à jour 2
Il semble qu'il ne soit pas possible d'utiliser les protocoles génériques Swift (ou mieux: associés au type) dans la programmation orientée objet basée sur un protocole.
Nous devons donc les emballer dans une sorte de conteneur et perdre l’approche basée sur les protocoles ou nous devons définir des protocoles différents pour chaque situation.
Parce que travailler sans protocole n'est pas une option pour moi, je dois écrire différents protocoles sans génériques. Honte à Swift ????
Je ne suis pas sûr que votre problème puisse être résolu sans effacement de types, car vous ne pouvez pas utiliser de protocoles avec des types associés pour des types de variables ou des paramètres de fonctions.
Essayez la solution avec effacement de type:
final class AnyDockable<U>: Dockable {
typealias T = U
let _dock: (U) -> Void
let _execute: () -> Void
init<Base: Dockable & Executable>(base: Base) where Base.T == U {
_dock = base.dock
_execute = base.execute
}
func dock(object: U) {
_dock(object)
}
func execute() {
_execute()
}
}
Votre compilateur sera content, je l'ai vérifié:
class Exe: Executable {
func execute() {
print("")
}
}
let executable: Executable = Exe()
let de = AnyDockable(base: DockableExecutable(executable))
final class MyViewController: UIViewController {
init(save: Executable, uiUpdateConnector: AnyDockable<Executable>) {
super.init(nibName: "", bundle: nil)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
MyViewController(save: executable, uiUpdateConnector: de)
Si je ne me trompe pas, vous recherchez Composition du protocole (conformité multiprotocole), non? Vous pouvez ensuite utiliser différents de vos décorateurs après.
Peut-être cherchez-vous ceci: Swift 3 protocol<A, B>
et dans Swift 4 A & B
:
final class MyViewController: UIViewController {
init(save: Executable, uiUpdateConnector: protocol<Dockable, Executable>) {}
}
http://braking.github.io/require-conformance-to-multiple-protocols/