2015-07-18 5 views
7

EDIT: Вот весь code example для Xcode 6.4viewDidLoad вызывается перед весь метод инициализации выполняется

У меня есть простое приложение IOS без раскадровки. Я поставил rootViewController для UIWindow в AppDelegate.swift, как это:

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 реализация класса выглядит следующим образом:

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") 
    } 

} 

При запуске приложения вывод консоли выглядит следующим образом:

viewDidLoad 
init(nibName: bundle:) 

Это означает, что строки после строки super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) вызывается после метода viewDidLoad! Это происходит только для классов, которые наследуются от UITabBarController. Если вы попробуете этот же пример с потоком UIViewController, все будет в порядке, а viewDidLoad вызывается после выполнения метода init.

ответ

8

У вас нет гарантии, что viewDidLoad будет вызываться только после завершения метода init. viewDidLoad вызывается, когда диспетчеру просмотра необходимо загрузить свою иерархию представлений.

Внутренний метод инициализации TabBarController (путем вызова super.init) выполняет то, что вызывает загрузку представления.

Это относится ко всем контроллерам вида. Например: если вы создаете подкласс UIViewController и делаете что-либо с его свойством view на init, например, добавляете подвью или просто устанавливаете свойство вида backgroundColor - вы заметите такое же поведение.

+1

спасибо. Но я считаю, что это противоречивое поведение и плохо документировано. Я отправляю TSI в Apple, и мне интересно увидеть их ответ. – Deny

+0

@Deny Мне бы хотелось услышать, что Apple должна сказать, когда они дадут вам ответ, но я подозреваю, что вы не получите много дополнительной информации. Это стандартное поведение iOS. Вы правы, хотя в отношении отсутствия документации для подкласса TabBarController. – Artal

1

Похоже, что init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) для UITabBarController вызывает по ошибке viewDidLoad. Если вы установите точку останова на своей линии print("viewDidLoad"), вы увидите, что вызов выполняется как часть последовательности инициализации.

Если вы меняете контроллер представления подкласса UIViewController вы увидите, что viewDidLoad не вызываются как часть последовательности инициализации, а как результат вызова makeKeyAndVisible

Я не знаю, почему Apple, закодирован его это но я подозреваю, что дать контроллеру панели вкладок возможность настроить ситуацию до загрузки контроллеров содержимого.

В любом случае, это просто то, что вы собираетесь иметь дело с тем, если вы хотите создать подкласс UITabBarController

+0

Вы правы. Я пришел к такому же выводу. Тем не менее, мне интересно, как комментируют инженеры Apple. Тогда я отправлю его здесь. – Deny

5

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

Это не должно вызывать удивления, но, видимо, UITabBarController имеет различное поведение, чем большинство контроллеров. Жизненный цикл в целом может быть «тем же» между ним и другими контроллерами представлений, но порядок, который он выполняет, не является.

То есть, когда вы создаете подкласс UITabBarController и предоставляете свой собственный инициализатор, вы заметите, что метод viewDidLoad вызван неожиданным образом. То есть, как только вы назовете [super init] (или другой инициализатор в UITabBarController), он вызовет loadView во время этой инициализации, которая затем приведет к вызову вашего viewDidLoad. Вероятно, это не то, что вы ожидаете, потому что большинство (все?) другие подклассы UIViewController не создают экземпляр своего представления во время процесса инициализации. Таким образом, если вы предоставили пользовательский инициализатор и ожидали выполнить некоторую настройку перед загрузкой представления, а затем, как только загрузка будет загружена, добавьте свои встроенные контроллеры представлений, это нарушит вашу логику.

Решение состоит в том, чтобы фактически перевести код установки из стандартного метода viewDidLoad и в специальный метод настройки, который вызывается в конце вашего пользовательского инициализатора. Это поражает меня как «запах кода», который Apple никогда не пропускала. Скорее всего, это связано с тем, что UITabBarController должен добавить UITabBar в представление UIViewController, которое требует, чтобы представление существовало. Это то, что срабатывает loadView.

Смежные вопросы