it-swarm.com.de

iPhone-AnsichtWird nicht ausgelöst

Ich habe zahlreiche Beiträge über Personen gelesen, die Probleme mit viewWillAppear haben, wenn Sie Ihre Ansichtshierarchie nicht erstellen nur richtig. Mein Problem ist, dass ich nicht herausfinden kann, was das bedeutet.

Wenn ich eine Variable RootViewController erstelle und addSubView auf diesem Controller aufrufe, würde ich erwarten, dass die hinzugefügten Ansichten für viewWillAppear-Ereignisse verkabelt werden. 

Hat jemand ein Beispiel für eine komplexe programmatische Ansichtshierarchie, die auf jeder Ebene erfolgreich viewWillAppear-Ereignisse empfängt?

Apples Docs besagt:

Warnung: Wenn die Ansicht, die zu einem View Controller gehört, direkt zu einer View-Hierarchie hinzugefügt wird, empfängt der View Controller diese Nachricht nicht. Wenn Sie der Ansichtshierarchie eine Ansicht einfügen oder hinzufügen und diese über einen Ansichtscontroller verfügt, sollten Sie diese Nachricht direkt an den zugehörigen Viewcontroller senden. Wenn Sie den View Controller nicht senden, wird die Anzeige der zugehörigen Animation verhindert.

Das Problem ist, dass sie nicht beschreiben, wie das geht. Was bedeutet "direkt"? Wie fügen Sie "indirekt" eine Ansicht hinzu?

Ich bin relativ neu für Cocoa und iPhone, daher wäre es schön, wenn es neben dem einfachen Hello World-Mist auch nützliche Beispiele von Apple gäbe.

111
chzk

Wenn Sie einen Navigationscontroller verwenden und seinen Stellvertreter festlegen, werden die Methoden view {Will, Did} {Appear, Disappear} nicht aufgerufen.

Sie müssen stattdessen die Delegierungsmethoden des Navigationscontrollers verwenden:

navigationController:willShowViewController:animated:
navigationController:didShowViewController:animated:
52
mmalc

Ich bin auf dasselbe Problem gestoßen. Senden Sie einfach eine viewWillAppear-Nachricht an Ihren View-Controller, bevor Sie ihn als Unteransicht hinzufügen. (Es gibt einen BOOL-Parameter, der dem View-Controller mitteilt, ob er animiert wird oder nicht.)

[myViewController viewWillAppear:NO];

Schauen Sie sich RootViewController.m im Metronom-Beispiel an. 

(Ich fand die Beispielprojekte von Apple wirklich toll. Es gibt viel mehr als HelloWorld;)

29
lajos

Ich habe endlich eine Lösung gefunden, die funktioniert!

UINavigationControllerDelegate

Ich denke, das Wichtigste dabei ist, den Delegierten der Nav Control auf den Viewcontroller zu setzen, in dem er sich befindet, und UINavigationControllerDelegate zu implementieren. Brillant! Ich bin so aufgeregt, dass ich endlich eine Lösung gefunden habe!

18
Chris

Ich hatte gerade das gleiche Problem. In meiner Anwendung habe ich 2 Navigationscontroller, und derselbe View-Controller wird in jedem von ihnen in einem Fall und nicht in dem anderen verwendet. Ich meine, wenn Sie den gleichen View-Controller in der ersten UINavigationController drücken, wurde viewWillAppear aufgerufen, aber nicht, wenn Sie in den zweiten Navigations-Controller schieben.

Dann bin ich auf diesen Beitrag gestoßen: UINavigationController sollte viewWillAppear/viewWillDisappear-Methoden aufrufen.

Und erkannte, dass mein zweiter Navigationscontroller viewWillAppear neu definiert hat. Die Überprüfung des Codes zeigte, dass ich nicht anrief 

[super viewWillAppear:animated];

Ich habe es hinzugefügt und es hat funktioniert!

Die Dokumentation sagt:

Wenn Sie diese Methode überschreiben, müssen Sie an einer beliebigen Stelle in Ihrer Implementierung Super aufrufen.

7
Antoine

Ich habe einen Navigationscontroller verwendet. Wenn ich zu einer anderen Datenebene wechseln oder meine benutzerdefinierte Ansicht anzeigen möchte, verwende ich Folgendes:

[self.navigationController pushViewController:<view> animated:<BOOL>];

Wenn ich das tue, bekomme ich die viewWillAppear-Funktion zum Auslösen. Ich nehme an, dass dies als "indirekt" gilt, da ich die eigentliche addSubView-Methode nicht selbst anrufe. Ich weiß nicht, ob dies zu 100% für Ihre Anwendung zutrifft, da ich nicht feststellen kann, ob Sie einen Navigationscontroller verwenden, aber vielleicht gibt es einen Hinweis.

5
Josh Gagnon

Erstens sollte sich die Registerkartenleiste auf der Stammebene befinden, dh dem Fenster hinzugefügt werden, wie in der Apple-Dokumentation angegeben. Dies ist der Schlüssel für ein korrektes Verhalten.

Zweitens: Sie können canUITabBarDelegate/UINavigationBarDelegate verwenden, um die Benachrichtigungen manuell weiterzuleiten, aber ich habe festgestellt, dass alles, was ich tun musste, manuell aufgerufen werden musste, um die gesamte Hierarchie der Ansichtsaufrufe korrekt auszuführen 

[tabBarController viewWillAppear:NO];
[tabBarController viewDidAppear:NO];

und

[navBarController viewWillAppear:NO];
[navBarController viewDidAppear:NO];

.. nur EINMAL vor dem Einrichten der View-Controller auf dem jeweiligen Controller (direkt nach der Zuordnung). Von da an ruft er diese Methoden korrekt auf seinen untergeordneten Ansichtscontrollern auf.

Meine Hierarchie ist wie folgt:

window
    UITabBarController (subclass of)
        UIViewController (subclass of) // <-- manually calls [navController viewWill/DidAppear
            UINavigationController (subclass of)
                UIViewController (subclass of) // <-- still receives viewWill/Did..etc all the way down from a tab switch at the top of the chain without needing to use ANY delegate methods

Beim ersten Aufruf der genannten Methoden auf dem Tab/Nav-Controller wurde sichergestellt, dass ALLE Ereignisse korrekt weitergeleitet wurden. Ich musste sie nicht mehr manuell über die Methoden UINavigationBarDelegate/UITabBarControllerDelegate aufrufen.

Randbemerkung: Seltsamerweise, wenn es nicht funktionierte, die private Methode 

- (void)transitionFromViewController:(UIViewController*)aFromViewController toViewController:(UIViewController*)aToViewController 

.. die Sie vom Callstack einer funktionierenden Implementierung aus sehen können, ruft normalerweise die viewWill/Did..-Methoden auf, aber nicht, bis ich die obigen Schritte ausgeführt habe (obwohl sie aufgerufen wurden).

Ich denke, es ist sehr wichtig, dass sich UITabBarController auf Fensterebene befindet und die Dokumente dies zu unterstützen scheinen.

Hoffe das war klar (ish), gerne weitere Fragen beantworten.

4
Sam

Ansichten werden "direkt" hinzugefügt, indem [view addSubview:subview]..__ aufgerufen wird. Ansichten werden "indirekt" durch Methoden hinzugefügt, z.

Jedes Mal, wenn Sie [view addSubview:subviewController.view] aufrufen, sollten Sie [subviewController viewWillAppear:NO] (oder YES je nach Fall) anrufen.

Dieses Problem hatte ich, als ich mein eigenes benutzerdefiniertes Root-View-Verwaltungssystem für einen Subscreen in einem Spiel implementierte. Das manuelle Hinzufügen des Aufrufs zu viewWillAppear hat mein Problem behoben.

3
AndrewS

Der richtige Weg ist die Verwendung der UIViewController-Containment-API. 

- (void)viewDidLoad {
     [super viewDidLoad];
     // Do any additional setup after loading the view.
     UIViewController *viewController = ...;
     [self addChildViewController:viewController];
     [self.view addSubview:viewController.view];
     [viewController didMoveToParentViewController:self];
}
3
Hari Kunwar

Da keine Antwort akzeptiert wird und Menschen (wie ich) hier landen, gebe ich meine Variation. Ich bin mir jedoch nicht sicher, ob dies das ursprüngliche Problem war. Wenn der Navigationscontroller als Unteransicht zu einer anderen Ansicht hinzugefügt wird, müssen Sie die Methoden viewWillAppear/Dissappear usw. wie folgt selbst aufrufen:

- (void) viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];

    [subNavCntlr viewWillAppear:animated];
}

- (void) viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];

    [subNavCntlr viewWillDisappear:animated];
}

Nur um das Beispiel zu vervollständigen. Dieser Code wird in meinem ViewController angezeigt, wo ich den Navigationscontroller in einer Ansicht erstellt und hinzugefügt habe, die ich in der Ansicht platziert habe. 

- (void)viewDidLoad {

    // This is the root View Controller
    rootTable *rootTableController = [[rootTable alloc]
                 initWithStyle:UITableViewStyleGrouped];

    subNavCntlr = [[UINavigationController alloc]   
                  initWithRootViewController:rootTableController];

    [rootTableController release];

    subNavCntlr.view.frame = subNavContainer.bounds;

    [subNavContainer addSubview:subNavCntlr.view];

    [super viewDidLoad];
}

die .h sieht so aus

@interface navTestViewController : UIViewController <UINavigationControllerDelegate> {
    IBOutlet UIView *subNavContainer;
    UINavigationController *subNavCntlr;
}

@end

In der Nib-Datei habe ich die Ansicht, und unter dieser Ansicht habe ich ein Bild und den Container (eine andere Ansicht), in den ich den Controller einfügt. Ich musste einige Dinge durcheinander bringen, da dies für einen Kunden Arbeit war.

alt text

3
hol

Vielen Dank iOS 13.

ViewWillDisappear, ViewDidDisappear, ViewWillAppear und ViewDidAppear werden auf einem Presenting View Controller unter iOS 13, der eine neue modale Präsentation verwendet, die nicht den gesamten Bildschirm abdeckt, nicht aufgerufen .

Credits gehen an Arek Holko . Er hat mir wirklich den Tag gerettet.

enter image description here

2
BilalReffas

Ich verwende diesen Code für Push- und Pop-View-Controller:

Drücken: 

[self.navigationController pushViewController:detaiViewController animated:YES];
[detailNewsViewController viewWillAppear:YES];

pop:

[[self.navigationController popViewControllerAnimated:YES] viewWillAppear:YES];

.. und es funktioniert gut für mich.

2

Ein sehr häufiger Fehler ist wie folgt ... Sie haben eine Ansicht, UIView* a, und eine andere, UIView* b. Sie fügen b zu a als Unteransicht hinzu. Wenn Sie versuchen, viewWillAppear in b aufzurufen, wird dies der Fall niemals gefeuert werden, weil es eine Unteransicht von a ist

2
giuseppe
[self.navigationController setDelegate:self];

Setzen Sie den Delegaten auf den Root-View-Controller.

1
Gaurav

Für Swift. Erstellen Sie zuerst das Protokoll, um das aufzurufen, was Sie in viewWillAppear aufrufen möchten

protocol MyViewWillAppearProtocol{func myViewWillAppear()}

Zweitens erstellen Sie die Klasse

class ForceUpdateOnViewAppear: NSObject, UINavigationControllerDelegate {
func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool){
    if let updatedCntllr: MyViewWillAppearProtocol = viewController as? MyViewWillAppearProtocol{
        updatedCntllr.myViewWillAppear()
    }
}

}

Drittens machen Sie die Instanz von ForceUpdateOnViewAppear zum Mitglied der entsprechenden Klasse, die Zugriff auf den Navigationscontroller hat, und existiert, solange der Navigationscontroller vorhanden ist. Dies kann beispielsweise der Root-View-Controller des Navigationscontrollers oder die Klasse sein, die ihn erstellt oder präsentiert. Weisen Sie dann der Instanz von Navigation Controller so früh wie möglich die Instanz von ForceUpdateOnViewAppear zu. 

1
Vadim Motorine

Ich denke, dass das Hinzufügen einer Unteransicht nicht notwendigerweise bedeutet, dass die Ansicht angezeigt wird, so dass die Methode der Klasse nicht automatisch aufgerufen wird

1
winston

Ich denke, was sie "direkt" meinen, ist, wenn man die Dinge genau wie die Xcode-Vorlage "Navigation Application" verbindet, wodurch der UINavigationController als einzige Unteransicht des UIWindow der Anwendung festgelegt wird.

Mit dieser Vorlage konnte ich nur die Will/Did/Appear/Disappear-Methoden aufrufen, die für das Objekt ViewControllers beim Push/Pop dieser Controller im UINavigationController aufgerufen werden. Keine der anderen Lösungen in den Antworten funktionierte für mich, einschließlich der Implementierung im RootController und der Weitergabe an den (untergeordneten) NavigationController. Diese Funktionen (werden/waren/erschienen/verschwinden) wurden nur in meinem RootController aufgerufen, wenn die VCs der höchsten Ebene, mein "Login" und die Navigations-VCs angezeigt wurden, nicht die Sub-VCs im Navigationscontroller. Daher hatte ich keine Gelegenheit dazu "Weiterleiten" an den Nav VC.

Am Ende habe ich die Delegate-Funktionalität von UINavigationController verwendet, um nach bestimmten Übergängen zu suchen, für die in meiner App Follow-Up-Funktionen erforderlich waren, und dies funktioniert, aber es erfordert etwas mehr Arbeit, um sowohl die verschwindende als auch die "simulierte" Funktionalität zu erhalten.

Es ist auch eine Frage des Prinzips, dass es funktioniert, nachdem ich heute stundenlang gegen dieses Problem geschlagen habe. Jeder Funktionscodeausschnitt, der einen benutzerdefinierten RootController und eine untergeordnete Navigation VC verwendet, ist sehr willkommen.

1
Bogatyr

Falls dies jemandem hilft. Ich hatte ein ähnliches Problem, bei dem meine ViewWillAppear nicht auf eine UITableViewController feuert. Nachdem ich viel herumgespielt hatte, wurde mir klar, dass das Problem darin bestand, dass die UINavigationController, die meine UITableView steuert, nicht in der Root-Ansicht ist. Sobald ich das behoben habe, funktioniert es jetzt wie ein Champion.

1
Andrew

Ich hatte dieses Problem gerade selbst und es dauerte 3 volle Stunden (davon 2 googeln), um das Problem zu beheben.

Was sich als Hilfe herausstellte, war, einfach die App vom Gerät/Simulator zu löschen, zu reinigen und anschließend erneut auszuführen .

Hoffentlich hilft das

1
Finn Gaida

Ich bin nicht zu 100% sicher, aber ich denke, dass das Hinzufügen einer Ansicht zur Ansichtshierarchie direkt den Aufruf von -addSubview: in der Ansicht des Ansichtscontrollers (z. B. [viewController.view addSubview:anotherViewController.view]) erfordert, anstatt einen neuen Ansichtscontroller auf den Stack der Navigationssteuerung zu verschieben.

1
Martin Gordon

ViewWillAppear ist eine Überschreibungsmethode der UIViewController-Klasse. Wenn Sie ein SubView hinzufügen, wird ViewWillAppear nicht aufgerufen. Wenn Sie jedoch Push, Pop, Show, SetFront oder PopToRootViewController aus einem ViewController aufrufen, wird ViewWillAppear für den angezeigten ViewController aufgerufen.

0
Abu Ul Hassan

Ich habe eine Klasse erstellt, die dieses Problem löst. Stellen Sie es einfach als Delegaten Ihres Navigationscontrollers ein und implementieren Sie eine oder zwei einfache Methoden in Ihrem Viewcontroller - diese werden aufgerufen, wenn die Ansicht kurz vor der Anzeige steht oder über NavigationController angezeigt wurde

Hier ist der Gist mit dem Code

0
GregJaskiewicz

In meinem Fall war das nur ein seltsamer Fehler im ios 12.1-Emulator. Nach dem Start auf einem echten Gerät verschwunden.

0
Burning

In meinem Fall war das Problem mit der benutzerdefinierten Übergangsanimation ..__ Wenn festgelegt, modalPresentationStyle = .customviewWillAppear nicht aufgerufen

in benutzerdefinierten Übergangsanimationsklassen müssen Aufrufmethoden aufgerufen werden: beginAppearanceTransition und endAppearanceTransition

0
ober