Da dies seit langem die akzeptierte Antwort ist, muss ich sie mit einer besseren Antwort korrigieren.
Einige Kommentare zur Notwendigkeit:
- Ihre Ansicht sollte nicht direkt auf den Ansichts-Controller zugreifen müssen.
- Die Ansicht sollte stattdessen unabhängig vom Ansichtscontroller sein und in verschiedenen Kontexten arbeiten können.
- Wenn Sie die Ansicht benötigen, um eine Schnittstelle zum Ansichts-Controller herzustellen, empfiehlt es sich, das Delegatenmuster zu verwenden.
Ein Beispiel für die Implementierung folgt:
@protocol MyViewDelegate < NSObject >
- (void)viewActionHappened;
@end
@interface MyView : UIView
@property (nonatomic, assign) MyViewDelegate delegate;
@end
@interface MyViewController < MyViewDelegate >
@end
Die Ansicht ist mit ihrem Delegaten (as UITableView
zum Beispiel), und es ist egal, ob sie im Ansichtscontroller oder in einer anderen Klasse implementiert ist, die Sie letztendlich verwenden.
Meine ursprüngliche Antwort lautet: Ich empfehle dies nicht, auch nicht die restlichen Antworten, bei denen ein direkter Zugriff auf den View Controller erreicht wird
Es gibt keine eingebaute Möglichkeit, dies zu tun. Während Sie um es durch Zugabe eines bekommen kann IBOutlet
auf der UIView
und verbindet diese im Interface Builder, ist dies nicht zu empfehlen. Die Ansicht sollte nichts über den Ansichts-Controller wissen. Stattdessen sollten Sie die von @Phil M vorgeschlagenen Schritte ausführen und ein Protokoll erstellen, das als Delegat verwendet werden soll.
Anhand des von Brock veröffentlichten Beispiels habe ich es so geändert, dass es eine Kategorie von UIView anstelle von UIViewController ist, und es rekursiv gemacht, sodass jede Unteransicht (hoffentlich) den übergeordneten UIViewController finden kann.
Um diesen Code zu verwenden, fügen Sie ihn in eine neue Klassendatei ein (ich habe meine "UIKitCategories" genannt) und entfernen Sie die Klassendaten ... kopieren Sie die @ Schnittstelle in den Header und die @ Implementierung in die .m-Datei. Importieren Sie dann in Ihrem Projekt "UIKitCategories.h" und verwenden Sie es im UIView-Code:
quelle
UIView
ist eine Unterklasse vonUIResponder
.UIResponder
legt die Methode-nextResponder
mit einer Implementierung fest, die zurückgibtnil
.UIView
Überschreibt diese Methode, wie inUIResponder
(aus irgendeinem Grund statt inUIView
) dokumentiert, wie folgt: Wenn die Ansicht über einen Ansichtscontroller verfügt, wird sie von zurückgegeben-nextResponder
. Wenn kein View Controller vorhanden ist, gibt die Methode die Übersicht zurück.Fügen Sie dies Ihrem Projekt hinzu und Sie können loslegen.
Hat jetzt
UIView
eine Arbeitsmethode zum Zurückgeben des View Controllers.quelle
UIView
und Empfangsbereich nichts in der Antwortkette befindetUIViewController
. Die Antwort von Phil M mit Rekursion ist der richtige Weg.Ich würde einen leichteren Ansatz zum Durchlaufen der gesamten Responderkette vorschlagen, ohne eine Kategorie in UIView hinzufügen zu müssen:
quelle
Wenn ich mehrere bereits gegebene Antworten kombiniere, versende ich sie auch mit meiner Implementierung:
Die Kategorie ist Teil meiner ARC-fähigen statischen Bibliothek, die ich für jede von mir erstellte Anwendung versende. Es wurde mehrmals getestet und ich habe keine Probleme oder Lecks gefunden.
PS: Sie müssen keine Kategorie wie ich verwenden, wenn die betreffende Ansicht eine Unterklasse von Ihnen ist. Im letzteren Fall fügen Sie die Methode einfach in Ihre Unterklasse ein und schon kann es losgehen.
quelle
Obwohl dies technisch gelöst werden kann, wie von pgb empfohlen, ist dies meiner Meinung nach ein Konstruktionsfehler. Die Ansicht sollte den Controller nicht kennen müssen.
quelle
Ich veränderte de Antwort , damit ich jede Ansicht, Button passieren kann, beschriften usw. es der Eltern zu bekommen
UIViewController
. Hier ist mein Code.Bearbeiten Sie die Swift 3-Version
Edit 2: - Schnelle Erweiterung
quelle
Vergessen Sie nicht, dass Sie für das Fenster, dessen Unteransicht die Ansicht ist, auf den Root-View-Controller zugreifen können. Wenn Sie beispielsweise einen Navigationsansichts-Controller verwenden und eine neue Ansicht darauf verschieben möchten:
Sie müssen jedoch zuerst die rootViewController-Eigenschaft des Fensters ordnungsgemäß einrichten. Tun Sie dies, wenn Sie den Controller zum ersten Mal erstellen, z. B. in Ihrem App-Delegaten:
quelle
[[self navigationController] view]
es sich um die "Haupt" -Ansicht (Unteransicht) des Fensters handelt, dierootViewController
Eigenschaft des Fensters festgelegt werden muss,navigationController
die die "Haupt" -Ansicht sofort steuert.Obwohl diese Antworten technisch korrekt sind, einschließlich Ushox, besteht meiner Meinung nach der genehmigte Weg darin, ein neues Protokoll zu implementieren oder ein vorhandenes wiederzuverwenden. Ein Protokoll isoliert den Beobachter von dem Beobachteten, ähnlich wie ein Mail-Slot dazwischen. Genau das macht Gabriel über den Aufruf der pushViewController-Methode. Die Ansicht "weiß", dass es das richtige Protokoll ist, Ihren Navigationscontroller höflich zu bitten, eine Ansicht zu pushen, da der Ansichtscontroller dem Navigationscontroller-Protokoll entspricht. Während Sie Ihr eigenes Protokoll erstellen können, ist es in Ordnung, nur Gabriels Beispiel zu verwenden und das UINavigationController-Protokoll erneut zu verwenden.
quelle
Ich bin auf eine Situation gestoßen, in der ich eine kleine Komponente habe, die ich wiederverwenden möchte, und habe Code in einer wiederverwendbaren Ansicht selbst hinzugefügt (es ist wirklich nicht viel mehr als eine Schaltfläche, die a öffnet
PopoverController
).Während dies auf dem iPad gut funktioniert (das
UIPopoverController
präsentiert sich selbst, benötigt daher keinen Verweis auf aUIViewController
), bedeutet es, dass derselbe Code plötzlich funktioniert, wenn SiepresentViewController
auf Ihren Code verweisenUIViewController
. Ein bisschen inkonsistent, oder?Wie bereits erwähnt, ist es nicht der beste Ansatz, Logik in Ihrem UIView zu haben. Aber es fühlte sich wirklich nutzlos an, die wenigen benötigten Codezeilen in einen separaten Controller zu packen.
In beiden Fällen handelt es sich um eine schnelle Lösung, mit der jeder UIView eine neue Eigenschaft hinzugefügt wird:
quelle
Ich denke nicht, dass es "schlecht" ist, herauszufinden, wer in einigen Fällen der View Controller ist. Was eine schlechte Idee sein könnte, ist, den Verweis auf diesen Controller zu speichern, da er sich ändern kann, wenn sich die Übersichten ändern. In meinem Fall habe ich einen Getter, der die Responderkette durchquert.
//.h
//.m
quelle
Die einfachste do while-Schleife zum Auffinden des viewControllers.
quelle
Swift 4
(prägnanter als die anderen Antworten)
Mein Anwendungsfall, für den ich zuerst auf die Ansicht zugreifen muss
UIViewController
: Ich habe ein Objekt, das sich umAVPlayer
/ wickelt,AVPlayerViewController
und ich möchte eine einfacheshow(in view: UIView)
Methode bereitstellen , in die eingebettetAVPlayerViewController
wirdview
. Dafür muss ich aufview
's zugreifenUIViewController
.quelle
Dies beantwortet die Frage nicht direkt, sondern nimmt eine Annahme über die Absicht der Frage an.
Wenn Sie eine Ansicht haben und in dieser Ansicht eine Methode für ein anderes Objekt aufrufen müssen, z. B. den Ansichtscontroller, können Sie stattdessen das NSNotificationCenter verwenden.
Erstellen Sie zuerst Ihre Benachrichtigungszeichenfolge in einer Header-Datei
Rufen Sie aus Ihrer Sicht postNotificationName auf:
Dann fügen Sie in Ihrem View Controller einen Beobachter hinzu. Ich mache das in viewDidLoad
Implementieren Sie jetzt (auch im selben View Controller) Ihre Methode copyString: wie im obigen @selector dargestellt.
Ich sage nicht, dass dies der richtige Weg ist, es scheint nur sauberer zu sein, als die Ersthelferkette hochzulaufen. Ich habe diesen Code verwendet, um einen UIMenuController in einer UITableView zu implementieren und das Ereignis wieder an den UIViewController zu übergeben, damit ich etwas mit den Daten tun kann.
quelle
Es ist sicherlich eine schlechte Idee und ein falsches Design, aber ich bin sicher, wir können alle eine schnelle Lösung der besten von @Phil_M vorgeschlagenen Antwort genießen:
Wenn Sie einfache Dinge tun möchten, z. B. einen modalen Dialog anzeigen oder Daten verfolgen möchten, ist die Verwendung eines Protokolls nicht gerechtfertigt. Ich persönlich speichere diese Funktion in einem Dienstprogrammobjekt. Sie können sie von allem verwenden, das das UIResponder-Protokoll implementiert, als:
Alle Gutschriften an @Phil_M
quelle
Vielleicht bin ich zu spät hier. Aber in dieser Situation mag ich keine Kategorie (Verschmutzung). Ich liebe diesen Weg:
quelle
Schnellere Lösung
quelle
sequence
Bit). Wenn also "schnell" "funktionaler" bedeutet, dann ist es wohl schneller.Aktualisierte Version für Swift 4: Danke für @Phil_M und @ paul-slm
quelle
Swift 4 Version
Anwendungsbeispiel
quelle
Zwei Lösungen ab Swift 5.2 :
return
Schlüsselwort ist jetzt nicht mehr erforderlich 🤓Lösung 1:
Lösung 2:
quelle
Auf Phils Antwort:
In der Zeile:
id nextResponder = [self nextResponder];
Wenn self (UIView) keine Unteransicht der ViewController-Ansicht ist, können Sie, wenn Sie die Hierarchie von self (UIView) kennen, auch Folgendes verwenden:id nextResponder = [[self superview] nextResponder];
...quelle
Meine Lösung würde wahrscheinlich als Schwindel angesehen werden, aber ich hatte eine ähnliche Situation wie Mayoneez (ich wollte die Ansicht als Reaktion auf eine Geste in einer EAGLView wechseln), und ich habe den Ansichts-Controller der EAGL folgendermaßen erhalten:
quelle
EAGLViewController *vc = [(EAGLAppDelegate *)[UIApplication sharedApplication].delegate viewController];
.ClassName *object
- mit einem Sternchen.Ich denke, es gibt einen Fall, in dem der Beobachtete den Beobachter informieren muss.
Ich sehe ein ähnliches Problem, bei dem die UIView in einem UIViewController auf eine Situation reagiert und zuerst ihren übergeordneten Ansichtscontroller anweisen muss, die Zurück-Schaltfläche auszublenden, und dann nach Abschluss dem übergeordneten Ansichtscontroller mitteilen muss, dass er sich vom Stapel entfernen muss.
Ich habe dies mit Delegierten ohne Erfolg versucht.
Ich verstehe nicht, warum das eine schlechte Idee sein sollte?
quelle
Eine andere einfache Möglichkeit besteht darin, eine eigene Ansichtsklasse zu haben und der Ansichtsklasse eine Eigenschaft des Ansichtscontrollers hinzuzufügen. Normalerweise erstellt der Ansichts-Controller die Ansicht, und hier kann sich der Controller auf die Eigenschaft festlegen. Anstatt nach dem Controller zu suchen (mit ein wenig Hacking), muss der Controller sich selbst auf die Ansicht einstellen - dies ist einfach, aber sinnvoll, da der Controller die Ansicht "steuert".
quelle
Wenn Sie dies nicht in den App Store hochladen möchten, können Sie auch eine private UIView-Methode verwenden.
quelle
quelle
Um den Controller einer bestimmten Ansicht abzurufen, kann die UIFirstResponder-Kette verwendet werden.
quelle
Wenn Ihr rootViewController UINavigationViewController ist, der in der AppDelegate-Klasse eingerichtet wurde, dann
Wo c View Controller-Klasse erforderlich.
VERWENDUNG:
quelle
Es gibt keine Möglichkeit.
Ich übergebe den UIViewController-Zeiger an UIView (oder eine entsprechende Vererbung). Es tut mir leid, dass ich bei der IB-Herangehensweise an das Problem nicht helfen kann, weil ich nicht an IB glaube.
Um den ersten Kommentator zu beantworten: Manchmal müssen Sie wissen, wer Sie angerufen hat, da dies bestimmt, was Sie tun können. Zum Beispiel haben Sie mit einer Datenbank möglicherweise nur Lesezugriff oder Lese- / Schreibzugriff ...
quelle