Asynchron und Kapselung. Best practice?

  • Asynchron und Kapselung. Best practice?

    Hi,

    ich habe hier gerade eine interessante Frage wo ich mal eure Meinungen hören möchte:

    Ich erzeuge ein Einstellungen-Popover mit einer TableView. Die Einstellungen die dort drin erscheinen, werden dynamisch aus dem Netz generiert. Das bedeutet, nach dem Öffnen des Popover wird zunächst ein Webrequest gestartet der die Einstellungen holt. Diese Einstellungen werden in einer eigenen Klasse nennen wir sie einfach Settigs gespeichert.
    Das kann bei schlechter Verbindung natürlich ein wenig dauern. Deshalb brauche ich einen Activity-Indicator mit Abbruch-Button. Diesen habe ich mir auch schon vor langer Zeit mal gemacht. Der ist ziemlich einfach. Er legt einfach ein halbtransparentes View über den ganzen Screen und zeigt in der Mitte dann ein viereckiges View mit Titel und Abbruch-Button. Damit ist gewährleistet, dass man während der Activityview dargestellt wird nichts anderes angeklickt werden kann als der Abbruch Button (Welcher beim Anklicken ein didCancel() an sein Delegate schickt).

    Soweit zur Vorgeschichte. Jetzt zur eigentlich Frage.

    Wenn man dieses Konzept nach MVC lösen würde, dann müßte der PopoverVewiController die Klasse Settings erzeugen, den ActivityView erzeugen und darstellen und dann eine Methode load in den Settings aufrufen, welche wiederum asynchron einen Webservice startet und beim beenden oder beim Abbruch via Delegate den PopoverViewController informiert, welcher dann die Einsellungen anzeigen kann. Das bedeutet aber einen ganz schön großen Aufwand an hin und hergeschicke von Messages.

    Wäre es nicht einfacher das alles in die Settingsklasse zu verlagern? Also der PopoverViewController erzeugt einfach eine Klasse Settings und ruft dann einen Load auf, der erst zurück kommt, wenn entweder abgebrochen wurde (Load liefert false zurück) oder die Settings geladen sind (load liefert true zurück).

    Das würde aber bedeuten, das die Settings in Ihrem load den ActivityView erzeugen und darstellen muss und dann in einem seperaten Thread den Webservice starten. Der load muss jetzt aber solange warten bis entweder der webservice fertig ist oder aber der Abbruch Button geklickt wurde. Kann man sowas machen oder ist das so richtig schlechter code? Wenn ja, wie macht man es am elegantesten?

    Oder meint ihr das ist sowiso Käse und nur MVC ruled? ;)

    Gruß

    Claus
    2 Stunden Try & Error erspart 10 Minuten Handbuchlesen.

    Pre-Kaffee-Posts sind mit Vorsicht zu geniessen :)
  • Thallius schrieb:

    Wenn man dieses Konzept nach MVC lösen würde, dann müßte der PopoverVewiController die Klasse Settings erzeugen, den ActivityView erzeugen und darstellen und dann eine Methode load in den Settings aufrufen, welche wiederum asynchron einen Webservice startet und beim beenden oder beim Abbruch via Delegate den PopoverViewController informiert, welcher dann die Einsellungen anzeigen kann. Das bedeutet aber einen ganz schön großen Aufwand an hin und hergeschicke von Messages.

    Das ist meiner Meinung nach die sauberere Lösung, weil sie die Trennung von Backend und Darstellung strikt einhält. Anstelle der Delegation kannst du ja auch einen Completion-Handler verwenden, was den Implementierungsaufwand doch etwas verringern dürfte.

    Thallius schrieb:

    Das würde aber bedeuten, das die Settings in Ihrem load den ActivityView erzeugen und darstellen muss und dann in einem seperaten Thread den Webservice starten. Der load muss jetzt aber solange warten bis entweder der webservice fertig ist oder aber der Abbruch Button geklickt wurde. Kann man sowas machen oder ist das so richtig schlechter code?

    Das finde ich ziemlich ungünstig. Wenn du noch andere Möglichkeiten (egal ob im Frontend oder Backend) zum Laden der Settings zu der App hinzufügen willst, dann bekommst du schnell zu so Ekligkeiten wie doppeltem Code, Fallunterscheidungsketten, Streuung von Frontend-Code im Backen, grauen Haaren, Mundgeruch und Zahnausfall. ;)
    „Meine Komplikation hatte eine Komplikation.“
  • macmoonshine schrieb:


    Thallius schrieb:

    Das würde aber bedeuten, das die Settings in Ihrem load den ActivityView erzeugen und darstellen muss und dann in einem seperaten Thread den Webservice starten. Der load muss jetzt aber solange warten bis entweder der webservice fertig ist oder aber der Abbruch Button geklickt wurde. Kann man sowas machen oder ist das so richtig schlechter code?

    Das finde ich ziemlich ungünstig. Wenn du noch andere Möglichkeiten (egal ob im Frontend oder Backend) zum Laden der Settings zu der App hinzufügen willst, dann bekommst du schnell zu so Ekligkeiten wie doppeltem Code, Fallunterscheidungsketten, Streuung von Frontend-Code im Backen, grauen Haaren, Mundgeruch und Zahnausfall. ;)


    Genau das finde ich eigentlioch anders herum Nehmen wir mal an ich brauche irgendwann ein zweites Set Settings. Dann könnte ich in diesem Fall einfach noch einen Parameter zum Load hinzufügen, der einfach einen anderen Webservice aufruft und alles andere wäre fertig. Im MVC Fall müßte ich dann im ViewController für diese anderen Settings wieder mich um den ganzen Hickhack mit dem ActivityView kümmern (Vorrausgesetzt ich kann nicht den gleichen ViewController dafür nehmen aber nehmen wir mal an das geht nicht weil in dem View noch andere Dinge drin sind oder so)

    Gruß

    Claus
    2 Stunden Try & Error erspart 10 Minuten Handbuchlesen.

    Pre-Kaffee-Posts sind mit Vorsicht zu geniessen :)
  • Also ich würde das auf keinem Fall mit MVC (Massive View Controller) machen. Das Laden der eigentlichen Settings aus dem Netz hat nix mit einer UI zu tun und sollte in einer eigenen Komponente erfolgen. Das kannst Du z.B. mit einer FSM umsetzen. Je nachdem werden dann gewisse Events getriggert (lädt noch, Einstellungen geladen, abgebrochen etc.) welche Du z.B. mit Delegation oder Blocks auslöst. Dein Viewcontroller hängt sich dann an die events und macht das, wofür er gedacht ist: das view verwalten (und nur das). Das kannst Du dann auch ganz einfach testen und erweitern.

    Zum Hin- und Hergeschicke von Messages: ist es nicht das, worum es bei OOP geht?
  • Markus Müller schrieb:

    Zum Hin- und Hergeschicke von Messages: ist es nicht das, worum es bei OOP geht?

    Nicht zwingend. Es geht bei OOP um Objekte.
    In Objective-C kommunizieren sie ganz gewaltig über Messages, ja. Wenn man sich mal sämtliche Notifications des Systems ausgeben lässt merkt man erst einmal, was für eine Laberbacke Mac OS X eigentlich ist.

    Das ist aber nur eine Möglichkeit der Kommunikation, nicht die einzige

    Thallius schrieb:

    Nehmen wir mal an ich brauche irgendwann ein zweites Set Settings

    Premature Optimization Is The Root Of All Evil (or at least most of it) In Programming.
    Ich meine, nehmen wir mal an die Website ist gar nicht erreichbar. Oder die gelieferten Daten entsprechen nicht dem, was Du erwartest. Oder statt einem zweiten Set Settings hast Du spontan 4 halbe Sets Settings um Speicherplatz zu sparen…
    Über gewisse Dinge sollte man sich erst dann Gedanken machen, wenn man sie wirklich benötigt.

    Zur View Controller Hierarchie: Der MVC Ansatz klingt ganz verlockend, ich verstehe lediglich Deine Bedenken nicht.

    Dein PopOverViewController macht nichts weiter, als das PopOverView zu steuern. Größe, Position, watweißich. Deine Tabelle wird über einen TableViewDataSource gefüllt. Wenn der jetzt statt Settings#1 Settings#2 anzeigen soll, dann lässt sich da doch bei gravierendem optischen Unterschied von Settings#1 und Settings#2 die Data Source austauschen.

    Wenn Du aber ein findiger Entwickler bist, ist natürlich alles so abgestimmt, dass Du an Deinem JSON schon ersehen kannst, ob ein Textfeld oder ein Switch oder ein Picker benötigt wird und kannst Dein TableView entsprechend gestalten – benötigst also lediglich eine Data Source für egal welches Settings Set.

    Deine Data Source arbeitet mit Objekten vom Typ Setting? Gut, prima, hervorragend. Auch dann ist es egal welches Settings Set es ist.
    Interessant ist hierbei also offenbar nur, woher die Daten kommen, aus denen die Settings Objekte generiert werden.
    Deine Settings Objekte haben allerdings überhaupt nichts mit dem UI am Hut. Also wirklich gar nichts. Überhaupt gar nichts.

    Wenn Du also einen Initializer + (instancetype) settingsFromURL:(NSURL*); einbauen möchtest, achte auf die Integration entsprechender Delegate-Methoden: - (void) settingsDidStartDownload:(Settings*); und - (BOOL) settings:(Settings*) didFinishDownload:(NSError*);.

    $Irgendein View Controller, der sich dafür berufen fühlt, spielt dann Delegate und dort blendest Du dann ein ActivityView ein oder aus.

    Alternativ geht bestimmt auch + (instancetype) settingsFromURL:(NSURL*) startHandler:^(void) completionHandler:^(BOOL, NSError*);
    Und dann halt in den Handlern arbeiten.

    Doch wie Markus Müller schon sagte: Das Laden der Settings aus dem Netz hat nix mit der UI zu tun.
    «Applejack» "Don't you use your fancy mathematics to muddle the issue!"

    Iä-86! Iä-64! Awavauatsh fthagn!

    kmr schrieb:

    Ach, Du bist auch so ein leichtgläubiger Zeitgenosse, der alles glaubt, was irgendwelche Typen vor sich hin brabbeln. :-P
  • Das mit dem "findigen Programmierer" ist zwar eine tolle Idee aber leider Wunschdenken. Denn der Webservice ist nicht von mir sondern wurde vom Auftraggeber bereits vor längerer Zeit für andere Clients als iOS in Java mit SOAP programmiert. Ich muss da also nehmen was kommt und das beste draus machen...

    Und eben weil das Laden eigentlich nichts mit dem UI zu tun hat finde ich es blöd, dass das UI wissen muss, dass es für diese Aktion einen ACtivityView aufmachen muss weil es länger dauern könnte. Eigentlich wäre es Sache der Settings Klasse das alle für sich zu handeln und dem View nur das Ergebnis zurück zu geben oder eben einen Fehler falls es nicht geklappt hat. Um alles andere spllte sich die Klase selber kümmern. Dazu würde dann aber eben auch das Anzeigen des Activity gehören und das würde mich wieder zu meinem Ausgangspost führen.

    Gruß

    Claus
    2 Stunden Try & Error erspart 10 Minuten Handbuchlesen.

    Pre-Kaffee-Posts sind mit Vorsicht zu geniessen :)
  • in Java mit SOAP programmiert

    Hö… :D
    [media]https://www.youtube.com/watch?v=_JaIJWo90D0[/media]

    - Klasse "Settings" erstellen
    - AppDelegate erzeugt Instanz "mySettings"
    - "mySettings" enthält den Quelltext, der das Zeugs lädt
    - Klasse "Settings" hat Methoden wie "startUpdate", "isUpdating", "stopUpdate"
    - diese Methoden senden "SettingsWillStartUpdate", "SettingsDidUpdate" etc.
    - schon beim Starten der Anwendung kann mit "startUpdate" begonnen werden
    - wird der ViewController erzeugt, der die Settings visualisiert, dann wird die Settings-Instanz übergeben
    - beim Zeigen des ViewControllers wird mit "isUpdating" geprüft und entsprechend das Warte-Ding gezeigt
    - kommt "SettingsDidUpdate" rein, dann kann das Warte-Ding ausgeblendet werden und der Anwender kann loslegen
    - wurden die Daten schon geladen, dann brauch es kein Warte-Ding

    Der ViewController hört nur auf Nachrichtigen, die auch von der übergebenen Settings-Instanz kommen.
    Somit kann bei Bedarf auch mehrere Setting-Instanzen verwendet werden.
    Das Laden der Settings hat meiner Meinung nach im ViewController selbst nichts zu suchen.

    Aber alles ein philosophisches Thema und sicherlich von der Ausgangssituation abhängig.
    Auch wenn es unbeliebt ist, aber werden die Settings an hunderten Stellen benötigt, dann ist ein Singelton sicherlich angenehmer.
    Es ist halt der Kompromiss zu finden, zwischen "gut umsetzbar" und "technisch abstrakt perfekt".

    Nur ma so als Ansatz…

    Viele Grüße