Ich habe ein Ray Wenderlich-Tutorial durchgearbeitet und festgestellt, dass der Autor Klassenerweiterungen verwendet, um Rückrufe von Stellvertretern zu speichern, anstatt sie in der Klasse selbst behandeln zu lassen, dh:
Rückrufe innerhalb der Klassenerweiterung delegieren:
extension LogsViewController : UIPopoverPresentationControllerDelegate {
func adaptivePresentationStyleForPresentationController(controller: UIPresentationController, traitCollection: UITraitCollection) -> UIModalPresentationStyle {
...
}
}
im Gegensatz dazu, dass es in der Klasse enthalten ist:
Rückrufe innerhalb der Klasse delegieren:
class LogsViewController : UITableViewController, UIPopoverPresentationControllerDelegate {
func adaptivePresentationStyleForPresentationController(controller: UIPresentationController, traitCollection: UITraitCollection) -> UIModalPresentationStyle {
...
}
}
Ich fand das seltsam und interessant zugleich. Er hat eine Datei, die nur den Erweiterungen in der LogsViewController-Klasse namens "LogsViewControllerExtension.swift" gewidmet ist, und hat für jedes Delegate-Protokoll eine andere Erweiterung: UITableViewDataSource, UISplitViewDelegate usw. Dh:
mehrere Klassenerweiterungen, die jeder mit Rückrufen in seiner eigenen Datei delegiert:
extension LogsViewController: UISplitViewControllerDelegate {
... callbacks
}
extension LogsViewController : UIPopoverPresentationControllerDelegate {
... callbacks
}
Warum?
Welche Vorteile bringt dies? Ich kann sehen, wo es vielleicht ein bisschen lesbarer ist, dies zu trennen, aber gleichzeitig ist es eine Ebene der Indirektion. Gibt es OO-Prinzipien, die dies unterstützen oder ablehnen?
quelle
Antworten:
Ich weiß nicht, warum Sie sagten, es füge eine Indirektionsebene hinzu. Vielleicht meinen Sie damit etwas anderes als die traditionelle Bedeutung, weil hierdurch keine zusätzliche Indirektion erzeugt wird. Aber warum?
Ich mache es, weil es modularer ist. Der gesamte Code, der für die Schnittstelle erforderlich ist, wird an einer einzigen Stelle gruppiert (mit Ausnahme der tatsächlichen Eigenschaften). Wenn ich später eine separate Klasse zum Implementieren dieses Protokolls auswähle (und somit eine tatsächliche Indirektionsebene einführe), muss ich nur noch alles tun Ändern Sie die Erweiterung in eine eigene Klasse (übergeben Sie die erforderlichen Eigenschaften über eine init-Funktion), und erstellen Sie im ViewController eine Eigenschaft, in die das Objekt instanziiert werden soll.
Ich habe auch alle privaten Funktionen, die nur von den Funktionen dieses Protokolls verwendet werden, in die Erweiterung eingefügt. Ich bin nicht so weit gegangen, eine vollständig separate Datei für die Erweiterung zu erstellen, aber dies macht deutlich, dass diese privaten Funktionen nur für dieses Protokoll bestimmt sind.
Und auf jeden Fall beschweren sich die Leute oft über fette View-Controller, und diese Aufteilung hilft dabei, die Organisation zu verbessern, auch wenn der View-Controller dadurch nicht dünner wird.
quelle
Wie Daniel in Bezug auf die Indirektion sagte, gibt es kein Niveau davon.
Ich stimme ihm zu und möchte eine zusätzliche leistungsstarke Funktion für Protokollerweiterungen hinzufügen, die ich kürzlich kannte.
Angenommen, Sie haben beispielsweise ein Protokoll
didCopyText
. Sie werden das implementieren als:In Swift sind Eigenschaften und Methoden nicht in der Protokolldeklaration implementiert. Sie möchten die Implementierung in jede Klasse schreiben, die
didCopyText
mit der übereinstimmt. Bei einer inkrementellen Anzahl von Klassen, die mit diesem Protokoll mit derselben Implementierung übereinstimmen, würde dies nur zu einem Durcheinander führen wiederholter Code. Hier bieten sich Protocol Extensions an.Mit der Implementierung der Eigenschaften und Methoden des Protokolls. Jede Klasse, die diesem Protokoll entspricht, verwendet dieselbe Implementierung.
quelle
Angenommen, Ihre Klasse unterstützt drei Protokolle, und deshalb müssen Sie drei Funktionssätze hinzufügen. Der einzige Zweck dieser Funktionen besteht in der Unterstützung eines Protokolls. Sie benötigen daher eine Dokumentation.
Wenn Sie jedoch für jedes Protokoll eine Erweiterung hinzufügen und in jeder Erweiterung genau die Funktionen implementieren, die für dieses eine Protokoll erforderlich sind, wird der Code viel besser lesbar.
Ich würde sie höchstwahrscheinlich nicht in separaten Dateien ablegen, es sei denn, diese Erweiterungen sind wirklich groß.
quelle