2016-09-19 1 views
2

Ich versuche, Informationen von Controller A zu Controller B zu übergeben. Die Sache ist, ich will:Informationen zwischen den Controllern Swifty (/ Protokoll) übergeben?

  • Concise: Um die Autovervollständigung von XCode bis zu einem gewissen Schlüsselinformationen zu minimieren. Ich möchte auf einfache Weise wissen, welche Parameter genau benötigt werden, bevor ich den Controller auf den Stapel schiebe.

  • Vermeiden Sie Übergänge. Aus meinem Verständnis ergeben sich im Storyboard viele Überschneidungen. Ich möchte nicht vom Storyboard abhängig sein, um Informationen weiterzugeben. (Jedes Mal, wenn ich Controller A zu einem anderen wechseln möchte, muss ich zum Storyboard gehen, um einige Änderungen vorzunehmen). Ich könnte meine App irgendwann in mehrere Storyboards aufteilen, und es kann ziemlich nervig sein, mit anderen umzugehen.

  • Schöne: Vielleicht Swift kann eine Swifty Lösung bieten, an die ich nicht gedacht habe.

  • Was ich zuerst versuchen wollte, war, Controller als Protokoll zu drücken. Auch wenn es nicht möglich ist, lassen Sie mich erklären:

  • Pushing ein Controller als Protokoll würde mir erlauben, genaue Sichtbarkeit meiner Attribute.

  • Es gibt keine enge Kopplung mit dem Storyboard

  • Viele Steuerungen (A, C, D), um eine B-Controller drücken möchten vielleicht verwandt ist, könnte ich sie jeden von ihnen ein anderes Protokoll geben Controller schieben B. Vielleicht könnte B unter anderen Umständen auftreten.

Zuerst wurde mein Code wie die Suche (die Storyboard-Erweiterung funktioniert):

if let myBCustomVC = storyboard.instanciateControllerWithIdentifier(MyBCustomVC.self) as? myVCustomFromAProtocol{ 
    myBCustomVC.AToB = self.data.count 
    self.navigationController?.pushViewController(myBCustomVC, animated: true) 
} 

protocol myVCustomFromAProtocol { 
    var AToB: Int {get set} 
} 

Die Sache ist, kann ich einen View-Controller gesenkten ein Protokoll nicht drücken. Ich musste mit einer hässlichen UINavigationController Erweiterung kommen. Hier ist das volle Ergebnis.

if let myBCustomVC = storyboard.instanciateControllerWithIdentifier(MyBCustomVC.self) as? myVCustomFromAProtocol{ 
    myBCustomVC.AToB = self.data.count 
    self.navigationController?.pushViewController(vcToPush: myBCustomVC, animated: true) 
} 

extension UINavigationController{ 
    func pushViewController(vcToPush: Any, animated: Bool){ 
     if let vc = vcToPush as? UIViewController{ 
      self.pushViewController(vc, animated: animated) 
     } 
    } 
} 

Seien wir ehrlich, während meine ersten beiden Ziele zu erreichen, ich habe einen ANY zu einem UIViewController, woosh downcasted.

Gibt es eine Möglichkeit enge Kopplung und Push-Controller auf dem Stapel in eine schönen Weise zu vermeiden, während eine eingeschränkte Sicht auf den Parameter zu halten von dem ersten View-Controller zu übergeben (A) zu dem zweiten (B). Was sind deine Gedanken? Warum sollte ich das nicht tun?

+1

Vielleicht ist dies von Wert für Sie: https://talk.objc.io/episodes/S01E05-connecting-view-controllers – Koen

Antwort

1

Mit Hilfe Fogmeister kam ich mit dieser Antwort auf. Es hat mehrere Vor- und Nachteile gegenüber der Verwendung eines Presenter-Objekts, das von einem Protokoll erbt.

Lösung: Verwenden Sie eine statische Factory-Methode (oder mehrere, abhängig vom Anwendungsfall), die sich in der zu instanziierenden Steuerung befinden.

Vorteile:

  • eine statische Factory-Methode verwenden erzwingen Parameter zu übergeben, die die eigentliche Steuerung wissen, für seine eigene Initialisierung erforderlich ist.
  • Keine Struktur (weniger Komplexität?)
  • Der konstante Gebrauch einer statischen Fabrikmethode wird mit der Zeit natürlich. Sie wissen, wenn Sie einen Controller betrachten, müssen Sie die Methode implementieren, um sie aufzurufen, und Sie kennen die erforderlichen Parameter. Sie müssen sich keine Gedanken darüber machen, welche Parameter implementiert werden müssen, um den Controller zu drücken. Implementieren Sie einfach die Funktion. Wenn Sie einen Präsentator verwenden, haben Sie dieses Wissen nicht, da die Parameter, die ausgepackt werden sollen, zahlreich sein können.
  • Die Verwendung eines Presenter ist näher an MVP und wird von der Dependency Injection Modell entfernt befürwortet von Apple (MVC)

Nachteile:

  • Die Verwendung der Presenter Muster vorgeschlagen von Fogmeister verwendet ein Protokoll. Das Protokoll bietet eine begrenzte Sichtbarkeit für Controller A (und alle Controller, die einen Controller B drücken möchten).
  • Die Verwendung des Modells Presenter bietet mehr Modularität und reduziert enge Kopplung. Controller A braucht nichts über Controller B zu wissen. Der Austausch von Controller B zu einem anderen Controller C kann erfolgen, ohne alle Controller zu beeinflussen, die nach B gingen (kann sehr nützlich sein, wenn Sie Ihre Anwendung oder in einigen Anwendungsfällen neu strukturieren)).

Hier ist meine aktuelle Implementierung in der Klasse:

im Regler B (statische Funktion):

static func prepareController(originController: UIViewController, AToB: Int) -> bVC? { 
    if let bVC = originController.storyboard?.instanciateControllerWithIdentifier(self) as? bVC{ 
     bVC.AToB = AToB 
     return bVC 
    } 
    else{ 
     return nil 
    } 
} 

In Controller A (die Steuerung auf dem Stapel schieben):

if let bVC = bVC(originController: self, AToB: *someValue*){ 
    self.navigationController?.pushViewController(bVC, animated: true) 
} 

Lösung muss mit einem Körnchen Salz genommen werden, lassen Sie mich wissen, was Sie @Fogmeister denken?

Beide Lösungen können kombiniert werden. Mit einer protokollierten Struktur, die die statische Methode des Controllers verwenden würde. Die Sache ist, dass es für Menschen, die Sie in das Projekt einführen, schnell zu komplex werden kann. Deshalb bleibe ich im Moment bei meiner Lösung. Ich betrachte jedoch Rahmenbedingungen für die Abhängigkeitsinjektion.

2

Ich würde dies von der anderen Seite (d. H. Die Seite des Controllers, die Sie präsentieren) nähern.

Sie könnten etwas wie ein Presenter Protokoll erstellen.

protocol Presenter { 
    func present(inContext context: UIViewController) 
    // possibly with some data in it too (if it's across all instances)... 
    var count: Int {get set} 
} 

und eine Art von Fabrik-Struktur auf der Oberseite jeweils ...

struct BVCPresenter: Presenter { 
    var count: Int = 0 

    func present(inContext context: UIViewController) { 
     // create the BViewController here 
     let controller = ... 

     context.push(controller, animated: true) 
    } 
} 

Oder etwas in diese Richtung. Es hängt wirklich von den Anwendungsfällen und die Daten um etc ...

A do ...

someGenericPresenter.present(inContext: navigationController) 

Der generische Moderator übergeben als Eigenschaft zu A kann oder kann also jetzt übergeben werden werden in eine Funktion als Parameter usw. übergeben werden ...

oder so etwas.

Man könnte sogar eine „FlowController“ erstellen, die diese Übergänge und Daten für Sie verwaltet ...

self.flowController.presentB() 

Die flowController dann weiß, welche B Bedürfnisse und wie und wo sie präsentieren und sie mit Daten füllen. Die einzelnen View-Controller müssen eigentlich nichts voneinander wissen.

Ich denke nicht, dass es eine Lösung dafür gibt, die allen Fällen entsprechen würde. Es erfordert viel Gedanken und Design. Aber es gibt viele Möglichkeiten. Denken Sie darüber nach, was Sie zwischen den View-Controllern benötigen und von wo aus arbeiten.

Auch nicht zu besorgt über die Schaffung von etwas, das "nur funktioniert", auch wenn es nicht Lehrbuch generisch ist, "Swifty", elegant, schön Code. Code zu haben, der funktioniert, ist viel besser als ein schön entworfenes System, das nicht funktioniert.

:)

+0

Vielen Dank für die schnelle Antwort und gute Idee. Ich werde versuchen, es umzusetzen und so schnell wie möglich zu Ihnen zurück zu kommen. –

+1

@SwiftSun viel Glück. Nehme meine Antwort nicht als konkrete Lösung, sondern arbeite an verschiedenen Ideen. Sieh dir auch das Video an, das im Kommentar zu deinem Q verlinkt ist :) Es gibt auch einige schöne WWDC-Videos, um thgouh zu durchsuchen. – Fogmeister

+0

Basierend auf Ihrer Antwort schlug ein Kollege vor, eine statische Methode in meinem Controller B zu verwenden (aus Sicht des Präsentators). Die statische Methode benötigt nur einen UINavigationController und die Parameter. Auf diese Weise kann ich verschiedene Implementierungen haben und ich kann nur die Parameter übergeben, die durch die statische Funktion spezifiziert sind. Auf diese Weise geht die gesamte Logik in den B-Controller und A muss sich nicht um die Implementierung kümmern. Großes Plus: keine Protokolle benötigt oder Struktur; Erzwingt, dass die Parameter übergeben werden, Protokolle erzwingen, dass vars keine Informationen weitergibt. Was denken Sie ? –

Verwandte Themen