schwarzer Bildschirm - Superview ist in ViewWillAppear Null

8

Ich habe eine Anwendung, die aus der Anwendungsvorlage mit Registerkarten erstellt wurde. (ARC, iOS 4)

  • Es gibt mehrere Registerkarten und auf den 2. Registerkarten viewcontroller.view (ViewCont2) gibt es eine Schaltfläche.
  • Diese Schaltfläche lädt die Ansicht eines anderen View-Controllers (ModalViewCont) mit der presentModalViewController-Methode.
  • Es gibt eine Schließen-Schaltfläche in ModalViewCont, die dispatchModalViewControllerAnimated aufruft.
  • In viewDidDisappear von ViewCont2 setze ich self.view = nil und andere outlets auf nil, um die Ansicht zu löschen, damit sie beim nächsten Mal auf dem Bildschirm erscheint. Ich mache das, weil es von einer Basisklasse (BaseViewCont) erbt, die einige allgemeine Eigenschaften des Ansichtscontrollers initialisiert und einige Buttons, Labels usw. in der viewDidLoad-Methode hinzufügt. ViewControllers, die von dieser Basisklasse erben, können diese Eigenschaften also in ihrer viewDidLoad-Methode anders als gewünscht konfigurieren.

Problem

Nun, wenn ModalViewCont auf dem Bildschirm erscheint, indem Sie die Home-Taste drücken, um die Anwendung im Hintergrund zu platzieren und nachdem Sie die Anwendung zurückgeholt haben, wird die ViewCont2-Ansicht nicht geschlossen, sondern ein schwarzer Bildschirm mit der Tableiste unten. Das gleiche passiert, ohne den Hintergrund / Vordergrund der Anwendung zu setzen; Wenn andere Tabs angetippt werden, bevor Sie auf die Registerkarte 2. tippen. ( BEARBEITEN: Dies geschieht nur, wenn self.view in der Ansicht "nill" auf "nil" anstelle von "viewDidDisappear" gesetzt ist.)

Ich habe festgestellt, dass ViewCont2 eine neue Ansicht lädt (die Referenz wurde überprüft), aber die Superansicht der Ansicht ist null, so dass die neue Ansicht nicht angezeigt wird, sondern ein schwarzer Bildschirm.

Dinge, die nicht funktioniert haben

  • Verwenden von [self.view removeFromSuperview]; bevor Sie self.view = nil einstellen,
  • In viewWillAppear Hinzufügen von Ansicht zum übergeordneten; [self.parentViewController.view addSubview: self.view]; Dieser funktionierte nicht reibungslos, die Ansicht wurde leicht oben auf dem Bildschirm platziert. Dies liegt daran, dass in der Hierarchie mehrere andere Superviews vorhanden sind.

Lösungen, die ich in Betracht gezogen habe;

  • 1- Wenn superview in viewDidLoad null ist, wird es in viewWillAppear (Annahme) verfügbar. Also, viewWillAppear-Methode von ViewCont2 könnte verwendet werden, um die Superview korrekt durch folgende geladen werden:

_

%Vor%
    Die
  • 2- viewWillAppear-Methode der Basisklasse könnte stattdessen für die Initialisierung verwendet werden, so dass die Ansicht nicht gelöscht werden muss. So kann die Leistung optimiert werden, sie wird nicht jedes Mal entfernt, wenn die Ansicht verschwindet. Außerdem wäre es besser, die Initialisierung nur einmal durchzuführen, indem Sie eine Markierung markieren, anstatt sie jedes Mal auszuführen, wenn sie erscheint.

Fragen

  • 1- Warum wird die Superview nicht wiederhergestellt? Was soll ich dafür tun? (Dies ist das Hauptproblem, das ich verstehen und lösen möchte, anstatt Alternativen auszuprobieren ...)
  • 2- Mache ich etwas falsch, indem ich null zum Anzeigen zum Entladen zuweise? Wenn ja, wie sollte ich die Ansicht in solch einem Fall (Registerkartenanwendung) richtig entladen?
  • 3- Stimmt etwas nicht mit der 1 überein? Lösung ? Scheint es wie ein Klotz? Ist diese Annahme über superview und viewWillAppear korrekt?

BEARBEITEN: Es scheint, dass wenn viewDidLoad früher aufgerufen wird als es sollte (d. h. wenn view in viewWillDisappear anstelle von viewDidDisappear angezeigt wird), superview nicht gesetzt ist.

    
lockedscope 16.08.2012, 13:52
quelle

6 Antworten

6

Es scheint seltsam, aber Ihr Vorschlag (1) ist in der Tat ein korrekter Workaround für dieses Problem:

%Vor%

Ihr zweiter Vorschlag ist gut für die Leistung (weil Laden von Ansichten ist eine teure Operation) - aber es wird das Problem nicht lösen. Sie können auch mit einem schwarzen Bildschirm enden, ohne die Ansicht in der folgenden Situation auf Null zu setzen (testen Sie dies im iOS-Simulator):

  1. öffne die modale Ansicht
  2. Simulieren Sie eine Speicherwarnung - & gt; Dadurch werden die Ansichten im tabbarcontroller
  3. entladen
  4. Drücken Sie die Home-Taste und öffnen Sie die App erneut
  5. modale Ansicht schließen - & gt; schwarzer Bildschirm

Im Allgemeinen können Sie davon ausgehen, dass in viewDidLoad die view -Eigenschaft festgelegt ist und in viewWillAppear + viewDidAppear die Ansicht der Ansichtshierarchie hinzugefügt wurde. Daher sollte der Superview zu diesem Zeitpunkt vorhanden sein (Hier ist der Superview eine private Ansicht des TabbarControllers der Klasse UIViewControllerWrapperView). In unserem Fall wird die Ansicht zwar neu geladen (zum Zeitpunkt der App-Wiederaufnahme), aber nicht zur Ansichtshierarchie hinzugefügt, was zu einem schwarzen Bildschirm führt. Dies scheint ein Fehler in UITabBarController zu sein.

Die Problemumgehung zwingt die Appearance Selectors erneut ausgeführt werden. Also wird viewWillAppear erneut aufgerufen, diesmal mit einer Superview. Auch viewDidAppear wird zweimal aufgerufen!

Das Einstellen von self.view auf null ist in Ordnung, sollte aber in den meisten Fällen nicht notwendig sein. Lassen Sie das System entscheiden, wann die Ansicht entladen werden soll (iOS kann Ansichten entladen, wenn der Speicher knapp wird). Der View-Controller-Code sollte so gestaltet sein, dass die Benutzeroberfläche jederzeit neu konfiguriert werden kann, ohne die Ansicht neu laden zu müssen.

    
Felix 24.08.2012, 21:46
quelle
1

Sie haben keine vollständige Kontrolle darüber, wann Ansichten geladen und entladen werden, und Sie dürfen Ansichten nicht manuell manuell laden / entladen.

Stattdessen sollten Sie sich das Laden / Entladen von Ansichten als etwas vorstellen, das vollständig Ihrem UIViewController s entspricht, wobei Sie nur für Folgendes verantwortlich sind:

  • Implementieren des tatsächlichen Ladens, indem Sie Ihre UIViewController-Unterklasse mit einer NIB-Datei verknüpfen oder loadView manuell implementieren.
  • Optionale Implementierung der Callbacks viewDidLoad , viewWillUnload und viewDidUnload , die vom View-Controller aufgerufen werden, wenn es entscheidet, seine Ansicht zu laden / zu entladen.

Die Tatsache, dass Sie keine vollständige Kontrolle über haben, wenn die oben genannten Callbacks aufgerufen werden, hat Auswirkungen darauf, was in sie gehen soll.

In Ihrem Fall, wenn ich es richtig verstehe, möchten Sie jedes Mal, wenn die Ansicht Ihres ViewCont2 verschwindet, es zurücksetzen, so dass es, wenn es wieder erscheint, in einem "sauberen" Zustand ist. Ich würde diesen Zustand in einigen Methoden implementieren, und rufen Sie beide von viewDidLoad und von viewDidDisappear . Alternativ können Sie die Logik "clean" in viewWillAppear haben.

Oder möchten Sie die ViewCont2-Ansicht nur bereinigen, wenn die aktuelle Schaltfläche angetippt wird? Löschen Sie in diesem Fall die Ansicht sowohl in viewDidLoad als auch, wenn Sie auf die Schaltfläche tippen.

    
Danra 24.08.2012 22:05
quelle
1

Ich biete an, dass, wenn der modale Ansichts-Controller aktiv ist und Sie die Ansicht ablehnen, dass Sie den Navigationsansicht-Controllern viewControllers eine neue Ansicht hinzufügen, diese Ansicht den Vorgänger entfernen soll.

Sie können mit meinem Projekt spielen, um zu sehen, ob Sie glauben, dass es für Sie funktioniert.

>

EDIT: Mein Kommentar zu der ausgewählten Antwort ist, dass diese Technik offensichtlich jetzt funktioniert, aber ich habe es selbst schwer, ihr zu folgen. Der Code in meinem Projekt verwendet das System auf einfache und direkte Weise - wenn die modale Ansicht aufgefordert wird, sich selbst zu verwerfen, ruft sie eine Methode auf (könnte in jeder Klasse sein), die dem Array des Navigationscontrollers eine neue Ansicht hinzufügt und sich dann selbst ablehnt . Für ein bisschen Zeit gibt es zwei View-Controller der gleichen Zeit, die neue über die alte gestapelt. Wenn der neue View-Controller erscheint, entfernt er im Hintergrund und unsichtbar den unerwünschten viewController vom Stapel der Nab-Leiste, und puh, er verschwindet.

    
David H 25.08.2012 02:26
quelle
1

Ich habe die tatsächliche Lösung für den UITabBarController-Fehler gefunden (Speicherwarnung, App, zurück / Vordergrund eingeben, Modal ablehnen). Die Ursache des Fehlers ist die Verwendung von UITabBarController als Root-View-Controller. Wir könnten also einen anderen View-Controller als Root-View-Controller verwenden und die Tab-Leiste daraus darstellen. Ich habe es auf iOS 5.1 Simulator getestet.

Natürlich ist der Overhead von extra UIViewController umstritten. Außerdem ist es gegen die Apple-Dokumentation;

  

Im Gegensatz zu anderen View-Controllern sollte ein Tab-Bar-Interface niemals als Kind eines anderen View-Controllers installiert werden. UITabBarController Klassenreferenz

%Vor%     
lockedscope 27.08.2012 15:52
quelle
0

Ich habe andere Lösungen gefunden;

  • Der erste bewirkt die Warnung: "Es wird erwartet, dass Anwendungsfenster am Ende des Anwendungsstarts einen Root-View-Controller haben", obwohl es einen Root-View-Controller gibt.

  • Obwohl es kludgy erscheint, wird der temporäre View-Controller mit dem ersten freigegeben.

  • Der zweite scheint vernünftiger.

.

%Vor%     
lockedscope 31.08.2012 16:56
quelle
-1

Ich denke, du solltest die Ansicht nicht null zuweisen. Wenn ich Sie richtig verstanden habe, möchten Sie den Inhalt jedes Mal aktualisieren / neu laden, wenn die Ansicht erscheint. Anstatt also die Ansicht auf null zu setzen, sollten Sie versuchen, sie zu aktualisieren. Sie können es tun, indem Sie hinzufügen:

%Vor%

Bitte sagen Sie mir, ob ich Ihr Problem richtig verstanden habe

    
arnoapp 19.08.2012 00:04
quelle

Tags und Links