Ich benutze das MVC-Muster für eine Weile auf verschiedenen Frameworks wie (swing, android, gwt ...) Jetzt lerne ich das iPhone-Framework und bin ziemlich überrascht über die MVC-Implementierung. Die Fragen, die ich stelle, betreffen die Interaktion zwischen View und Controller.
Zuerst stelle ich mir das MVC-Muster so vor:
Die Ansicht und der Controller kommunizieren miteinander über eine Schnittstelle (eine für die Ansicht und eine andere für die Steuerung)
In meiner Vorstellung des MVC-Musters muss der Controller das Attribut der Ansicht nicht kennen. (Der Controller kann beispielsweise keine Label-Attributinstanz der Ansicht haben, kann aber die Ansicht auffordern, den Wert dieser Bezeichnung über eine Methode der Ansichtsschnittstelle zu ändern)
Der Vorteil, den Controller nicht direkt an Ansichts-UI-Elementen arbeiten zu lassen, ist eine geringe Kopplung und daher ist es möglich, die Ansicht einfacher zu testen. Die Ansicht kann nach Isolation (oder mit einem Mock-Controller) gestartet und getestet werden.
Der Punkt ist, auf dem iPhone die Controller (ViewController zum Beispiel) wissen direkt die UI-Elemente daher mein Unverständnis. Mein Ziel ist es nicht, einen Rahmen zu kritisieren, den ich gerade lerne. Aber wenn das wirklich funktioniert, wie ich es beschrieben habe, finde ich das nicht wirklich sauber ...
Gibt es jemanden, der mehr mit diesem Framework experimentiert, der mir Details / Erklärungen geben kann? Oder wenn Sie sich mit meinem MVC-Ansatz nicht einverstanden fühlen, sagen Sie mir;)
Außerdem frage ich, ob meine Herangehensweise MVP nahekommt (hier beschrieben: Ссылка ) als MVC.
MVC hat verschiedene Dinge gemeint, da es zuerst in Smalltalk formalisiert wurde > und die NeXTSTEP (Cocoa) Version von MVC passt nicht genau zu Smalltalk. Smalltalks Zusammenbruch ist im Grunde so:
NeXTSTEPs Zusammenbruch ist in der Praxis eher so:
Ich unterscheide hier zwischen Zeichnen und Präsentieren, weil NSView dazu tendiert, über die "Bedeutung" der Daten dumm zu sein. Es konzentriert sich nur auf das Zeichnen von Pixeln. Sie tendieren dazu, tatsächliche Strings anstelle eines Objekts zu übergeben, das die Ansicht zerreißt und "präsentiert".
Es ist kein großer Unterschied, aber es ist die Ursache von Dingen wie dem, in das Sie hineingeraten. Die Hauptverschiebung IMO ist, dass mit Cocoa / NeXTSTEP die Ansichtsklassen mehr und mehr wiederverwendbar sind. Indem sie so wiederverwendbar wurden, mussten mehr der anwendungsempfindlichen Bereiche in den Controller ausgelagert werden. Dies ist meiner Meinung nach im Allgemeinen ein Vorteil, da es in den meisten Fällen zu weniger Unterklassen, besser verständlichem Code und mehr wiederverwendbarem Code führt. Insbesondere erlaubt es Ihnen, leichter Ansichten zu wechseln, die raffinierter gezeichnet werden (eine Ansicht, die einen bestimmten Weg animiert oder Farben in Reihen od. Dgl. Alterniert), ohne auf anwendungsspezifische Logik zu stoßen, die in der Regel in den Controllern lebt. p>
Das heißt, wenn eine Ansicht besonders komplex ist, finde ich es nützlich, spezialisiertere Ansichten zu erstellen, die ein Datenobjekt aufnehmen und ihre eigene Präsentation verwalten, mehr in der Art, wie ich glaube, dass Sie sich vorstellen.
EDIT: Eine zusätzliche Sache zu beachten. Der Beispielcode von Apple ist in Sachen Design oft schrecklich. Sie enthalten fast nie Modellklassen und stopfen fast alles vorstellbare in den ViewControllern und schlechter: der AppController (der meiner Meinung nach ein sehr einfaches Objekt sein sollte). Dies ist in der Regel, weil ihre Beispielcode versucht, einen bestimmten Punkt zu zeigen, und sie wollen nicht die Komplexität der Dinge zu brechen (oder der Autor ist faul, wählen Sie). Obwohl ich der Meinung bin, dass intelligente Ansichts-Controller oft gut funktionieren, sollten Sie den Beispielcode nicht als Beispiel dafür nehmen. Leider gibt es nicht viele kanonische Beispiele für gutes Cocoa-Design auf Anwendungsebene, da die meisten Cocoa-Apps Closed Source sind. Ein gutes Beispiel, von dem man lernen kann, ist Adium . Es ist ein hervorragendes Beispiel für eine große, gut gestaltete Cocoa-App mit mehreren Entwicklern.
Der iPhone ViewController soll eine Sammlung von Ansichten verwalten, die alle zu einer kohärenten Oberfläche kombiniert werden. Beispielsweise kann ein Ansichtscontroller eine Bildlaufansicht mit einem Dutzend Etikettenansichten, einer Wechselansicht und zwei Schaltflächenansichten verwalten. Jedes von UIView abgeleitete Stück behandelt die Zeichnung eines bestimmten Elements auf dem Bildschirm - eine Schaltfläche, eine Bildlaufebene, eine Beschriftung -, wobei der View-Controller steuert, welche Daten wohin gebracht werden. Daher konzentriert sich eine von UIViewController abgeleitete Klasse auf die Präsentation (mehr im MVC-Sinn), indem sie Daten in die richtigen UIView-Objekte (wie einen Controller) migriert. Ich denke, ViewController ist ein passender Begriff dafür .
Um einen einzelnen Bildschirm zu verwalten, wird ein UIViewController manchmal mehrere andere UIViewController für bestimmte Teile der Anzeige haben. Der UINavigationController beispielsweise verwaltet einen Stapel von UIViewControllern, von denen jeder eine Seite der Anzeige behandelt. Bei Cocoa dreht sich alles um Schichten.
Ein UIViewController kann und hat oft einen Delegaten (und manchmal eine Datenquelle ), mit dem er fragt, welche Daten zu den Ansichten gehören und Benutzereingaben filtern . In meinen Augen sind die Delegierten dadurch näher an den MVC-Controllern, da sie die Klassen sind, die alle Modelle verwalten und jede Anwendungs- (Geschäfts-) Logik enthalten. Das AppDelegate ist das große, das den gesamten Status der Anwendung verwaltet. Das AppDelegate behält möglicherweise alle Daten im Auge oder kann Teile der Daten an andere Delegierte weitergeben. Ich würde erwarten, dass die Facebook-App einen Delegierten für die Verwaltung aller Events, einen weiteren für Wall-Posts und einen dritten für Fotos hat, von denen jeder bis zum AppDelegate für die Kommunikation mit Facebook-Servern berichtet.
Wenn ich meine Apps schreibe, tendiere ich dazu, CoreData für das MVC-Modell, Delegaten für die MVC-Controller zu verwenden und die MVC-Ansichten an UIViewControllers zu übergeben, die damit beschäftigt sind, die Herden von UIViews zu verwirren.
Es ist kein Controller, es ist ein View-Controller. Dies ist entweder explizit im Klassennamen (UIViewController, UITableViewController) oder implizit (UITabBarController, da eine UITabBar eine Ansicht ist; UINavigationController, da Navigation ein Paradigma ist und der UINavigationController eine sehr dünne Sicht hat).
Der einzige Nicht-View "Controller", an den ich denken kann, ist ein NSFetchedResultsContoller.
Aber warum das seltsame Design?
Ein Teil davon hat mit dem iPhone-UI-Paradigma zu tun: Benutzer interagieren mit einem Bildschirm nach dem anderen. Wenn ein "Screenful" nicht sichtbar ist, kann der größte Teil des Speichers zurückgewonnen werden. UIViewControllers stellen einen Bildschirm dar und verwalten, wie Bildschirm-Vollbilder mit anderen Bildschirm-Vollbildern interagieren.
(Sicher, Apple hat dies auf dem iPad leicht erweitert, um Popovers / Split-Views zu implementieren, aber die beiden sind immer noch "screenfuls" anstelle von generischen Views. View-Controller sind vage analog zu Windows auf einem Desktop-OS, abgesehen von den meisten Sie sind die meiste Zeit nicht sichtbar.)
Ein Teil davon hat mit CoreAnimation zu tun: Ein UIView behandelt Zeichnung / Layout und wird von CALayers unterstützt. CALayers repräsentieren strukturierte Polys auf der GPU; der "Ebeneninhalt" (d. h. Textur) kann nicht willkürlich in den freien Speicher entladen werden. (Ich bin mir nicht ganz sicher, warum, aber es bedeutet, dass Sie den Inhalt einmal auf CGImage setzen können und es in Ruhe lassen.) Da viele der Eigenschaften der Ansicht durch Layer-Eigenschaften (frame, bounds, center, contentStretch, .. .), es ist ein bisschen albern, eine Ansicht ohne eine Ebene existieren zu lassen. Das Endergebnis ist, dass Ansichten schwergewichtig sind und sie gelegentlich verschwinden müssen, wenn der Speicher knapp ist. Daher muss der Ansichtscontroller Dinge im Auge behalten, die beim Laden / Laden der Ansicht erhalten bleiben sollen (Bildlaufposition, aktuell ausgewähltes Element, ...). Ja, es könnte die Ansicht veranlassen, sich selbst zu serialisieren, aber Serialisierung ist icky und die meisten Dinge müssen nicht serialisiert werden.
Ein Teil davon hat mit Faulheit zu tun: Sie müssen den View-Controller implementieren, um zu handhaben, wie er mit anderen View-Controllern interagiert. Auf der anderen Seite machen Ansichten die Autoresierung - wenn Sie das Layout in der nib oder in -viewDidLoad festlegen, müssen Sie oft keine benutzerdefinierte Ansicht schreiben. Faulheit diktiert, dass Sie nicht, so Layout häufig passiert in der Ansicht Controller.
Ich persönlich führe eine "intelligente" Sichtweise ein, wenn es sinnvoller erscheint. Nehmen Sie zum Beispiel die Wetter-App: Wenn die Ansicht geladen wird, müssen Sie das Wetter für eine Reihe von Tagen in jeder Zelle anzeigen (die eine Tabellenansichtszelle sein kann oder nicht; das spielt keine Rolle). Wenn Sie ein Update erhalten, müssen Sie alle Zellen aktualisieren. Sie könnten - [WeatherViewController updateCell:] implementieren, aber es scheint viel sinnvoller zu sein, nur - [WeatherCell setWeather:] und übergeben Sie Ihr Modell. Es gibt viel weniger Unordnung im View-Controller.
Ich gebe auch der Faulheit und Wartbarkeit den Vorwurf: Manchmal ist es einfach, alles in einer Datei zu haben, und manchmal ist halb-duplizierter Code mit geringfügigen Spezialisierungen einfacher als das Schreiben einer generischen Ansicht, die alle Anwendungsfälle unterstützt. Es ist viel netter als Enterprise Java, wo es eine Funktion gibt, die eine Funktion aufruft, die eine Funktion aufruft, die eine Funktion aufruft, die instanziiert ist (function-of-a-singleton) -mit-einer-Fabrik-mit-einer-Klasse-das-Sie-müssen-nach-unten-verfolgen-das-ruft-eine-Funktion-das-ruft-eine-Funktion auf, um herauszufinden, dass die Enterprise Software verwendet ein Kennwort-Hashing-Algorithmus, der in 1 Zeile von Python ausgedrückt werden kann. (Ich übertreibe nur leicht.)
(Was passiert also, wenn du entscheidest, dass das allgemeine Layout der Wetterzelle geeignet ist, etwa Mondphase / Sichtbarkeit anzuzeigen? Verschiebe das generische Zeug in eine Superklasse und mach eine Astronomerzelle oder was auch immer.)
Auch wenn Ihre Ansichten nicht mit einem Mock-Controller funktionieren können, tun Sie es falsch. Ansichten sollten nicht über ihren Ansichtscontroller wissen. Der View-Controller sollte sich selbst als Aktionsziel registrieren (addAction: target: forControlEvents :, denke ich) oder einen geeigneten Delegaten. Keiner von denen erwartet, dass das Ziel ein View-Controller ist.
Das ist nur eine Vermutung. Aber meine Vermutung ist, dass ein Grund dafür, dass der View und der Controller in Mac / iPhone-Implementierungen enger gekoppelt sind, darin besteht, dass Sie, wenn Sie die Interaktionskontrolle und die Präsentation zu sehr entkoppeln, mit einem hässlichen und weniger intuitiven Gefühl enden Schnittstelle erhöht sich. Während eine engere Kopplung den Entwickler dazu anspornt, die Kontrolle des Modells stärker auf subtile Unterschiede im Benutzerverhalten zuzuschneiden, da ihre Wahrnehmung auf die Ansichtsdarstellung reagiert. Sie erhalten mehr benutzerfreundlichen, aber weniger portablen Code. Werturteile erforderlich.
Tags und Links iphone model-view-controller mvp