2015-07-18 13 views
7

EDIT: Hier ganze ist code example für Xcode 6.4viewDidLoad wird aufgerufen, bevor ganz init-Methode ausgeführt wird

Ich habe einfach iOS-Anwendung ohne Storyboards. Ich habe rootViewController für UIWindow in AppDelegate.swift wie folgt aus:

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool { 
    let tabBarController = TabBarController() 

    window = UIWindow(frame: UIScreen.mainScreen().bounds) 
    window?.rootViewController = tabBarController 
    window?.makeKeyAndVisible() 

    return true 
} 

TabBarController Klasse Implementierung ist wie folgt:

viewDidLoad 
init(nibName: bundle:) 

It:

class TabBarController: UITabBarController { 

    override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) { 
     super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) 

     // Next line is called after 'viewDidLoad' method 
     println("init(nibName: bundle:)") 
    } 

    required init(coder aDecoder: NSCoder) { 
     fatalError("init(coder:) has not been implemented") 
    } 

    override func viewDidLoad() { 
     super.viewDidLoad() 
     println("viewDidLoad") 
    } 

} 

Wenn ich Anwendung laufen die Konsolenausgabe wie folgt aussieht bedeutet, dass Zeilen nach der Zeile super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) nach viewDidLoad Methode aufgerufen werden! Dies tritt nur für Klassen auf, die von UITabBarController erben. Wenn Sie das gleiche Beispiel mit UIViewController Nachkommen versuchen, ist alles in Ordnung und viewDidLoad wird aufgerufen, nachdem die Init-Methode ausgeführt wurde.

Antwort

8

Sie können nicht garantieren, dass viewDidLoad nur aufgerufen wird, nachdem die init-Methode ausgeführt wurde. viewDidLoad wird aufgerufen, wenn ein View-Controller seine Ansichtshierarchie laden muss.

Intern, TabBarController 's Init-Methode (durch den Aufruf von super.init) tut etwas, was verursacht, dass die Ansicht geladen wird.

Dies gilt für alle View-Controller. Beispiel: Wenn Sie eine UIViewController Unterklasse erstellen und mit der Eigenschaft view alles auf init tun, z. B. eine Unteransicht hinzufügen oder einfach nur die Eigenschaft backgroundColor der Ansicht festlegen, werden Sie das gleiche Verhalten bemerken.

+1

Vielen Dank. Aber ich denke, das ist inkonsistentes Verhalten und ist nicht gut dokumentiert. Ich sende TSI an Apple und ich bin daran interessiert, ihre Antwort zu sehen. – Deny

+0

@Deny Ich würde gerne hören, was Apple zu sagen hat, wenn sie Ihnen eine Antwort geben, aber ich vermute, dass Sie nicht viele zusätzliche Informationen erhalten werden. Dies ist ein Standardverhalten von iOS. Sie haben jedoch recht, wenn es um die fehlende Dokumentation für die TabBarController-Unterklassen geht. – Artal

1

Es scheint, dass init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) für einen UITabBarController aus irgendeinem Grund viewDidLoad aufruft. Wenn Sie in Ihrer Zeile print("viewDidLoad") einen Haltepunkt setzen, sehen Sie, dass der Aufruf als Teil der Initialisierungssequenz erfolgt.

Wenn Sie Ihre View-Controller ändern UIViewController Unterklasse Sie werden sehen, dass viewDidLoad nicht als Teil der Initialisierungssequenz genannt wird, sondern vielmehr als ein Ergebnis des Aufrufs makeKeyAndVisible

Ich weiß nicht, warum Apple es diese codierte so, aber ich vermute, es ist, den Tab-Bar-Controller eine Möglichkeit zu geben, Dinge einzurichten, bevor die Content-View-Controller geladen werden.

Egal, es ist nur etwas, das Sie mit beschäftigen müssen gehen, wenn Sie Unterklasse wollen UITabBarController

+0

Sie haben Recht. Ich bin zu demselben Schluss gekommen. Trotzdem bin ich gespannt auf Apple-Ingenieure, die kommentieren. Ich werde es dann hier posten. – Deny

5

Von: http://www.andrewmonshizadeh.com/2015/02/23/uitabbarcontroller-is-different/

Dies nicht überraschen sollte, aber anscheinend hat UITabBarController ein anderes Verhalten als die meisten View-Controller. Der Lebenszyklus kann insgesamt derselbe sein wie zwischen ihm und anderen View-Controllern, aber die Reihenfolge, in der er ausgeführt wird, ist nicht identisch.

Das heißt, wenn Sie eine Unterklasse von UITabBarController erstellen und Ihren eigenen benutzerdefinierten Initialisierer bereitstellen, werden Sie feststellen, dass die Methode viewDidLoad auf unerwartete Weise aufgerufen wird. Das heißt, sobald Sie [super init] (oder einen anderen Initialisierer auf UITabBarController) aufrufen, ruft sie während dieser Initialisierung loadView auf, was dann dazu führt, dass Ihr viewDidLoad aufgerufen wird. Dies ist wahrscheinlich nicht das, was Sie erwarten würden, weil die meisten (alle?)) andere UIViewController-Unterklassen instanziieren ihre Ansicht während des Initialisierungsprozesses nicht. Wenn Sie also einen benutzerdefinierten Initialisierer bereitstellen und einige Einstellungen vor dem Laden der Ansicht vornehmen möchten, und wenn die Ansicht geladen ist, fügen Sie die enthaltenen Ansichtscontroller hinzu, wodurch Ihre Logik zerstört wird.

Die Lösung besteht darin, Ihren Setup-Code aus der ViewDidLoad-Standardmethode in eine spezielle Setup-Methode zu verschieben, die am Ende des benutzerdefinierten Initialisierers aufgerufen wird. Dies erscheint mir als ein "Code-Geruch", den Apple niemals hätte durchlassen dürfen. Dies liegt wahrscheinlich daran, dass der UITabBarController der UIViewController-Ansicht eine UITabBar hinzufügen muss, die die Existenz der Ansicht erfordert. Was ist das, was loadView auslöst?

Verwandte Themen