Von UIView zu UIViewController gelangen?

185

Gibt es eine eingebaute Möglichkeit, von einem UIViewzu seinem zu gelangen UIViewController? Ich weiß, dass Sie von UIViewControllerzu seiner UIViewVia gelangen können, [self view]aber ich habe mich gefragt, ob es eine umgekehrte Referenz gibt.

bertrandom
quelle

Antworten:

46

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 IBOutletauf der UIViewund 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.

pgb
quelle
26
Das ist ein sehr schlechter Rat. Sie sollten einen Ansichts-Controller nicht aus einer Ansicht heraus referenzieren
Philippe Leybaert
6
@ MattDiPasquale: Ja, es ist schlechtes Design.
Philippe Leybaert
23
@Phillipe Leybaert Ich bin gespannt auf Ihre Gedanken zum besten Design für ein Button-Click-Ereignis, das eine Aktion auf dem Controller auslösen sollte, ohne dass die Ansicht einen Verweis auf den Controller enthält. Vielen Dank
Jonathon Horsman
3
@PhilippeLeybaert Apples Beispielprojekte demonstrieren in der Regel die Verwendung bestimmter API-Funktionen. Viele, auf die ich Bezug genommen habe, opfern gutes oder skalierbares Design, um eine prägnante Demonstration des Themas zu bieten. Ich habe lange gebraucht, um das zu realisieren, und obwohl es Sinn macht, finde ich es unglücklich. Ich denke, viele Entwickler nehmen diese pragmatischen Projekte als Apples Leitfaden für die beste Designpraxis, und ich bin mir ziemlich sicher, dass dies nicht der Fall ist.
Benjohn
11
All das bs über "du solltest das nicht tun" ist genau das. Wenn eine Ansicht etwas über ihren Ansichts-Controller wissen möchte, muss der Programmierer entscheiden. Zeitraum.
Daniel Kanaan
203

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.

@interface UIView (FindUIViewController)
- (UIViewController *) firstAvailableUIViewController;
- (id) traverseResponderChainForUIViewController;
@end

@implementation UIView (FindUIViewController)
- (UIViewController *) firstAvailableUIViewController {
    // convenience function for casting and to "mask" the recursive function
    return (UIViewController *)[self traverseResponderChainForUIViewController];
}

- (id) traverseResponderChainForUIViewController {
    id nextResponder = [self nextResponder];
    if ([nextResponder isKindOfClass:[UIViewController class]]) {
        return nextResponder;
    } else if ([nextResponder isKindOfClass:[UIView class]]) {
        return [nextResponder traverseResponderChainForUIViewController];
    } else {
        return nil;
    }
}
@end

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:

// from a UIView subclass... returns nil if UIViewController not available
UIViewController * myController = [self firstAvailableUIViewController];
Phil M.
quelle
47
Ein Grund, warum Sie dem UIView erlauben müssen, sich seines UIViewControllers bewusst zu werden, besteht darin, dass Sie benutzerdefinierte UIView-Unterklassen haben, die eine modale Ansicht / einen modalen Dialog verschieben müssen.
Phil M
Genial, ich musste auf meinen ViewController zugreifen, um ein benutzerdefiniertes Popup anzuzeigen, das von einer Unteransicht erstellt wurde
aryaxt
2
Ist das nicht eine schlechte Praxis für eine UIView, eine modale Ansicht zu pushen? Ich mache das gerade, aber ich denke, es ist nicht das Richtige.
Van Du Tran
6
Phil, Ihre benutzerdefinierte Ansicht sollte eine Delegatenmethode aufrufen, die der Ansichtscontroller abhört und von dort aus weiterleitet.
Malhal
9
Ich liebe es einfach, wie viele SO-Fragen einen "weisen Mann", eine akademische, akzeptierte Antwort mit nur wenigen Punkten und eine zweite Antwort haben, die praktisch, schmutzig und gegen die Regeln ist, mit dem Zehnfachen der Punkte :-)
hariseldon78
114

UIViewist eine Unterklasse von UIResponder. UIResponderlegt die Methode -nextRespondermit einer Implementierung fest, die zurückgibt nil. UIViewÜberschreibt diese Methode, wie in UIResponder(aus irgendeinem Grund statt in UIView) 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.

@interface UIView (APIFix)
- (UIViewController *)viewController;
@end

@implementation UIView (APIFix)

- (UIViewController *)viewController {
    if ([self.nextResponder isKindOfClass:UIViewController.class])
        return (UIViewController *)self.nextResponder;
    else
        return nil;
}
@end

Hat jetzt UIVieweine Arbeitsmethode zum Zurückgeben des View Controllers.

Brock
quelle
5
Dies funktioniert nur, wenn sich zwischen Empfangs- UIViewund Empfangsbereich nichts in der Antwortkette befindet UIViewController. Die Antwort von Phil M mit Rekursion ist der richtige Weg.
Olivier
33

Ich würde einen leichteren Ansatz zum Durchlaufen der gesamten Responderkette vorschlagen, ohne eine Kategorie in UIView hinzufügen zu müssen:

@implementation MyUIViewSubclass

- (UIViewController *)viewController {
    UIResponder *responder = self;
    while (![responder isKindOfClass:[UIViewController class]]) {
        responder = [responder nextResponder];
        if (nil == responder) {
            break;
        }
    }
    return (UIViewController *)responder;
}

@end
de.
quelle
22

Wenn ich mehrere bereits gegebene Antworten kombiniere, versende ich sie auch mit meiner Implementierung:

@implementation UIView (AppNameAdditions)

- (UIViewController *)appName_viewController {
    /// Finds the view's view controller.

    // Take the view controller class object here and avoid sending the same message iteratively unnecessarily.
    Class vcc = [UIViewController class];

    // Traverse responder chain. Return first found view controller, which will be the view's view controller.
    UIResponder *responder = self;
    while ((responder = [responder nextResponder]))
        if ([responder isKindOfClass: vcc])
            return (UIViewController *)responder;

    // If the view controller isn't found, return nil.
    return nil;
}

@end

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.

Constantino Tsarouhas
quelle
1
Dies ist die beste Antwort. Keine Notwendigkeit für eine Rekursion, diese Version ist schön optimiert
zeroimpl
12

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.

Ushox
quelle
Ich bin mir nur nicht sicher, wie dem viewController mitgeteilt werden kann, dass eine seiner Ansichten verschwindet und er eine seiner viewXXXAppear / viewXXXDisappear-Methoden aufrufen muss.
Mahboudz
2
Dies ist die Idee hinter dem Observer-Muster. Der Beobachtete (in diesem Fall die Ansicht) sollte seine Beobachter nicht direkt kennen. Der Beobachter sollte nur die Rückrufe erhalten, an denen er interessiert ist.
Ushox
12

Ich veränderte de Antwort , damit ich jede Ansicht, Button passieren kann, beschriften usw. es der Eltern zu bekommen UIViewController. Hier ist mein Code.

+(UIViewController *)viewController:(id)view {
    UIResponder *responder = view;
    while (![responder isKindOfClass:[UIViewController class]]) {
        responder = [responder nextResponder];
        if (nil == responder) {
            break;
        }
    }
    return (UIViewController *)responder;
}

Bearbeiten Sie die Swift 3-Version

class func viewController(_ view: UIView) -> UIViewController {
        var responder: UIResponder? = view
        while !(responder is UIViewController) {
            responder = responder?.next
            if nil == responder {
                break
            }
        }
        return (responder as? UIViewController)!
    }

Edit 2: - Schnelle Erweiterung

extension UIView
{
    //Get Parent View Controller from any view
    func parentViewController() -> UIViewController {
        var responder: UIResponder? = self
        while !(responder is UIViewController) {
            responder = responder?.next
            if nil == responder {
                break
            }
        }
        return (responder as? UIViewController)!
    }
}
Varun Naharia
quelle
7

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:

    [[[[self window] rootViewController] navigationController] pushViewController:newController animated:YES];

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:

-(void) applicationDidFinishLaunching:(UIApplication *)application {
    window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    RootViewController *controller = [[YourRootViewController] alloc] init];
    [window setRootViewController: controller];
    navigationController = [[UINavigationController alloc] initWithRootViewController:rootViewController];
    [controller release];
    [window addSubview:[[self navigationController] view]];
    [window makeKeyAndVisible];
}
Gabriel
quelle
Es scheint mir, dass gemäß Apple Docs, da [[self navigationController] view]es sich um die "Haupt" -Ansicht (Unteransicht) des Fensters handelt, die rootViewControllerEigenschaft des Fensters festgelegt werden muss, navigationControllerdie die "Haupt" -Ansicht sofort steuert.
Adubr
6

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.

Papa Schlumpf
quelle
6

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 UIPopoverControllerpräsentiert sich selbst, benötigt daher keinen Verweis auf a UIViewController), bedeutet es, dass derselbe Code plötzlich funktioniert, wenn Sie presentViewControllerauf Ihren Code verweisen UIViewController. 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:

extension UIView {

    var viewController: UIViewController? {

        var responder: UIResponder? = self

        while responder != nil {

            if let responder = responder as? UIViewController {
                return responder
            }
            responder = responder?.nextResponder()
        }
        return nil
    }
}
Kevin R.
quelle
5

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

@property (nonatomic, readonly) UIViewController * viewController;

//.m

- (UIViewController *)viewController
{
    for (UIResponder * nextResponder = self.nextResponder;
         nextResponder;
         nextResponder = nextResponder.nextResponder)
    {
        if ([nextResponder isKindOfClass:[UIViewController class]])
            return (UIViewController *)nextResponder;
    }

    // Not found
    NSLog(@"%@ doesn't seem to have a viewController". self);
    return nil;
}
Rivera
quelle
4

Die einfachste do while-Schleife zum Auffinden des viewControllers.

-(UIViewController*)viewController
{
    UIResponder *nextResponder =  self;

    do
    {
        nextResponder = [nextResponder nextResponder];

        if ([nextResponder isKindOfClass:[UIViewController class]])
            return (UIViewController*)nextResponder;

    } while (nextResponder != nil);

    return nil;
}
Mohd Iftekhar Qurashi
quelle
4

Swift 4

(prägnanter als die anderen Antworten)

fileprivate extension UIView {

  var firstViewController: UIViewController? {
    let firstViewController = sequence(first: self, next: { $0.next }).first(where: { $0 is UIViewController })
    return firstViewController as? UIViewController
  }

}

Mein Anwendungsfall, für den ich zuerst auf die Ansicht zugreifen muss UIViewController: Ich habe ein Objekt, das sich um AVPlayer/ wickelt, AVPlayerViewControllerund ich möchte eine einfache show(in view: UIView)Methode bereitstellen , in die eingebettet AVPlayerViewControllerwird view. Dafür muss ich auf view's zugreifen UIViewController.

frouo
quelle
3

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

#define SLCopyStringNotification @"ShaoloCopyStringNotification"

Rufen Sie aus Ihrer Sicht postNotificationName auf:

- (IBAction) copyString:(id)sender
{
    [[NSNotificationCenter defaultCenter] postNotificationName:SLCopyStringNotification object:nil];
}

Dann fügen Sie in Ihrem View Controller einen Beobachter hinzu. Ich mache das in viewDidLoad

- (void)viewDidLoad
{
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(copyString:)
                                                 name:SLCopyStringNotification
                                               object:nil];
}

Implementieren Sie jetzt (auch im selben View Controller) Ihre Methode copyString: wie im obigen @selector dargestellt.

- (IBAction) copyString:(id)sender
{
    CalculatorResult* result = (CalculatorResult*)[[PercentCalculator sharedInstance].arrayTableDS objectAtIndex:([self.viewTableResults indexPathForSelectedRow].row)];
    UIPasteboard *gpBoard = [UIPasteboard generalPasteboard];
    [gpBoard setString:result.stringResult];
}

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.

Shaolo
quelle
3

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:

static func firstAvailableUIViewController(fromResponder responder: UIResponder) -> UIViewController? {
    func traverseResponderChainForUIViewController(responder: UIResponder) -> UIViewController? {
        if let nextResponder = responder.nextResponder() {
            if let nextResp = nextResponder as? UIViewController {
                return nextResp
            } else {
                return traverseResponderChainForUIViewController(nextResponder)
            }
        }
        return nil
    }

    return traverseResponderChainForUIViewController(responder)
}

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:

if let viewController = MyUtilityClass.firstAvailableUIViewController(self) {}

Alle Gutschriften an @Phil_M

Paul Slm
quelle
3

Vielleicht bin ich zu spät hier. Aber in dieser Situation mag ich keine Kategorie (Verschmutzung). Ich liebe diesen Weg:

#define UIViewParentController(__view) ({ \
UIResponder *__responder = __view; \
while ([__responder isKindOfClass:[UIView class]]) \
__responder = [__responder nextResponder]; \
(UIViewController *)__responder; \
})
Lee
quelle
3

Schnellere Lösung

extension UIView {
    var parentViewController: UIViewController? {
        for responder in sequence(first: self, next: { $0.next }) {
            if let viewController = responder as? UIViewController {
                return viewController
            }
        }
        return nil
    }
}
Igor Palaguta
quelle
Ich mag diese Antwort. Ich bin mir nicht sicher, ob es schneller ist. Swift ist ein weiteres, das sich nicht entscheiden kann, welches von mehreren Paradigmen es mit Sprachen verheiratet sein will. In diesem Fall haben Sie eine schöne Demonstration eines funktionaleren Ansatzes (das sequenceBit). Wenn also "schnell" "funktionaler" bedeutet, dann ist es wohl schneller.
Travis Griggs
2

Aktualisierte Version für Swift 4: Danke für @Phil_M und @ paul-slm

static func firstAvailableUIViewController(fromResponder responder: UIResponder) -> UIViewController? {
    func traverseResponderChainForUIViewController(responder: UIResponder) -> UIViewController? {
        if let nextResponder = responder.next {
            if let nextResp = nextResponder as? UIViewController {
                return nextResp
            } else {
                return traverseResponderChainForUIViewController(responder: nextResponder)
            }
        }
        return nil
    }

    return traverseResponderChainForUIViewController(responder: responder)
}
dicle
quelle
2

Swift 4 Version

extension UIView {
var parentViewController: UIViewController? {
    var parentResponder: UIResponder? = self
    while parentResponder != nil {
        parentResponder = parentResponder!.next
        if let viewController = parentResponder as? UIViewController {
            return viewController
        }
    }
    return nil
}

Anwendungsbeispiel

 if let parent = self.view.parentViewController{

 }
levin varghese
quelle
2

Zwei Lösungen ab Swift 5.2 :

  • Mehr auf der funktionalen Seite
  • Das returnSchlüsselwort ist jetzt nicht mehr erforderlich 🤓

Lösung 1:

extension UIView {
    var parentViewController: UIViewController? {
        sequence(first: self) { $0.next }
            .first(where: { $0 is UIViewController })
            .flatMap { $0 as? UIViewController }
    }
}

Lösung 2:

extension UIView {
    var parentViewController: UIViewController? {
        sequence(first: self) { $0.next }
            .compactMap{ $0 as? UIViewController }
            .first
    }
}
  • Diese Lösung erfordert zuerst das Durchlaufen jedes Responders und ist daher möglicherweise nicht die leistungsstärkste.
Jason z
quelle
1

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];...

durchhängen
quelle
0

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:

EAGLViewController *vc = ((EAGLAppDelegate*)[[UIApplication sharedApplication] delegate]).viewController;
Gulchrider
quelle
2
Bitte schreiben Sie Ihren Code wie folgt um : EAGLViewController *vc = [(EAGLAppDelegate *)[UIApplication sharedApplication].delegate viewController];.
Jonathan Sterling
1
Das Problem liegt nicht bei der Punktsyntax, sondern bei den Typen. In Ziel C ein Objekt deklarieren, das Sie schreiben ClassName *object- mit einem Sternchen.
Adubr
Hoppla ... genau das hatte ich, aber das StackOverflow HTML-Widget sieht so aus, als hätte das Sternchen Kursivschrift bedeutet ... Ich habe es in einen Codeblock geändert, jetzt wird es korrekt angezeigt. Vielen Dank!
Gulchrider
0

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?

user7865437
quelle
0

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".

Jack
quelle
0

Wenn Sie dies nicht in den App Store hochladen möchten, können Sie auch eine private UIView-Methode verwenden.

@interface UIView(Private)
- (UIViewController *)_viewControllerForAncestor;
@end

// Later in the code
UIViewController *vc = [myView _viewControllerForAncestor];

quelle
0
var parentViewController: UIViewController? {
    let s = sequence(first: self) { $0.next }
    return s.compactMap { $0 as? UIViewController }.first
}
Klaudas
quelle
Obwohl dieser Code die Frage beantworten könnte, sollte eine gute Antwort auch erklären, was der Code tut und wie er das Problem löst.
BDL
0

Um den Controller einer bestimmten Ansicht abzurufen, kann die UIFirstResponder-Kette verwendet werden.

customView.target(forAction: Selector("viewDidLoad"), withSender: nil)
Adobels
quelle
-1

Wenn Ihr rootViewController UINavigationViewController ist, der in der AppDelegate-Klasse eingerichtet wurde, dann

    + (UIViewController *) getNearestViewController:(Class) c {
NSArray *arrVc = [[[[UIApplication sharedApplication] keyWindow] rootViewController] childViewControllers];

for (UIViewController *v in arrVc)
{
    if ([v isKindOfClass:c])
    {
        return v;
    }
}

return nil;}

Wo c View Controller-Klasse erforderlich.

VERWENDUNG:

     RequiredViewController* rvc = [Utilities getNearestViewController:[RequiredViewController class]];
Ansari Awais
quelle
-5

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 ...

John Smith
quelle
10
Was bedeutet das - "Ich glaube nicht an IB"? Ich habe es gestartet, es existiert auf jeden Fall.
März
5
Sie brauchen ein besseres Verständnis für Spaß und Abstraktion, insbesondere in Bezug auf die englische Sprache. Es bedeutet, dass ich es nicht mag.
John Smith
4
Ich mag keine Avocados. Aber ich wette, ich kann jemandem helfen, Guacamole zu machen. Dies kann in IB erfolgen, daher ist Ihre Antwort "Es gibt keinen Weg" offensichtlich falsch. Ob Sie IB mögen oder nicht, spielt keine Rolle.
Feloneous Cat