представление, чье представление не находится в предупреждении об иерархии окон

Я новичок в программировании и быстроте, и я пытался прочитать некоторые решения в переполнении стека, но, честно говоря, я не очень понимаю ответ :(

У меня есть 2 контроллера представления. homeVC и LoginVC. homeVC — мой начальный контроллер представления. в viewDidLoad у меня есть функция firebase, которая может проверить, входил ли пользователь в систему раньше или нет. если нет, то пользователь будет отправлен на loginVC. вот мой упрощенный код в HomeVC

import UIKit
import Firebase


class HomeVC: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        // to check whether the user has already logged in or not
        Auth.auth().addStateDidChangeListener { (auth, user) in
            if user == nil {
                let login = self.storyboard?.instantiateViewController(withIdentifier: "login") as! LoginVC
                self.present(login, animated: true, completion: nil)
            }
        }

        print("user enter homeVC")

    }



}

а вот мой логинVC

import UIKit
import Firebase
import GoogleSignIn

class LoginVC : UIViewController, GIDSignInUIDelegate {

    @IBOutlet weak var googleButton: GIDSignInButton!
    @IBOutlet weak var emailButton: UIButton!



    override func viewDidLoad() {
        super.viewDidLoad()


         // delegate declaration
         GIDSignIn.sharedInstance().uiDelegate = self

    }

    @IBAction func googleButtonDidPressed(_ sender: Any) {
        GIDSignIn.sharedInstance().signIn()
    }




}

приложение может работать так, как я ожидал. но в моей области отладки есть предупреждение:

Предупреждение: Попытка представить LoginVC: 0x7fc315714f40 на HomeVC: 0x7fc3155095c0, вид которого не находится в иерархии окон!

конечно проблема в этих строках кода

let login = self.storyboard?.instantiateViewController(withIdentifier: "login") as! LoginVC
self.present(login, animated: true, completion: nil)

насколько я знаю, если представление сложено в слое контроллера навигации, то, если я хочу перейти к другому контроллеру представления, я должен использовать метод perform segue.

Но для этого случая между homeVC и LoginVC не укладывается один и тот же навигационный контроллер. так что никакой иерархии. Вот почему я использую эту строку кода для перехода к другому контроллеру представления (loginVC). но я не понимаю, почему сказано, что "представление не находится в иерархии окон!"

Итак, что мне делать, чтобы пропустить это предупреждение?


person Alexa289    schedule 18.01.2018    source источник
comment
представление еще не готово в viewDidLoad. Попробуйте тот же код в viewDidAppear   -  person harsha yarabarla    schedule 18.01.2018


Ответы (6)


Ваш LoginVC в полном порядке.

Однако вам нужно изменить свой HomeVC, как предложил @Sh_Khan, и переместить код тестирования с viewDidLoad на viewDidAppear:

import UIKit
import Firebase

class HomeVC: UIViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
    }
    
    // HomeVC.view was added to a view hierarchy
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        
        // to check whether the user has already logged in or not
        Auth.auth().addStateDidChangeListener { (auth, user) in
            if user == nil {
                let login = self.storyboard?.instantiateViewController(withIdentifier: "login") as! LoginVC
                self.present(login, animated: true, completion: nil)
            }
        }
    }
}

Пояснение

Ваш метод viewDidLoad вызывается до того, как будет представлен viewController, поэтому в этот момент он не может реально представить другой контроллер представления (поскольку он сам не представлен), viewDidLoad документация:

Вызывается после загрузки представления контроллера в память.

Этот метод вызывается после того, как контроллер представления загрузил свою иерархию представлений в память. Этот метод вызывается независимо от того, была ли иерархия представлений загружена из файла пера или создана программно в методе loadView(). Обычно вы переопределяете этот метод, чтобы выполнить дополнительную инициализацию представлений, которые были загружены из файлов пера.

В этот момент viewController еще не находится в иерархии окон.

Однако viewDidAppear вызывается при представлении view и становится частью иерархии окон, viewDidAppear документация:

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

Вы можете переопределить этот метод для выполнения дополнительных задач, связанных с представлением представления. Если вы переопределяете этот метод, вы должны вызвать super в какой-то момент своей реализации.

Не забудьте вызвать super.viewDidAppear во время переопределения.

person Milan Nosáľ    schedule 18.01.2018

Переместить код в viewDidAppear

 override func viewDidAppear(_ animated:Bool) {
    super.viewDidAppear(true)
  // to check whether the user has already logged in or not
    Auth.auth().addStateDidChangeListener { (auth, user) in
        if user == nil {
            let login = self.storyboard?.instantiateViewController(withIdentifier: "login") as! LoginVC
            self.present(login, animated: true, completion: nil)
        }
    }

    print("user enter homeVC")

}
person Sh_Khan    schedule 18.01.2018

TLDR; Вы должны переместить свой код в viewDidAppear

viewDidLoad()

Этот метод вызывается после того, как контроллер представления загрузил свою иерархию представлений в память. Этот метод вызывается независимо от того, была ли иерархия представлений загружена из файла пера или создана программно в методе loadView(). Обычно вы переопределяете этот метод, чтобы выполнить дополнительную инициализацию представлений, которые были загружены из файлов пера. документы Apple

Таким образом, представление пока находится только в памяти, а не в иерархии. Вы должны переместить его в viewDidAppear

viewDidAppear()

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

person Haagenti    schedule 18.01.2018

Как сказал Sh_Khan, переместите строки:

let login = self.storyboard?.instantiateViewController(withIdentifier: "login") as! LoginVC
self.present(login, animated: true, completion: nil)

в методе viewDidAppear(); когда вызывается viewDidLoad(), контроллер представления еще не добавлен в иерархию представлений, он не виден и не может представить другой контроллер представления.

person Rico Crescenzio    schedule 18.01.2018

Причина такой ошибки: вы пытаетесь представить (открыть) два контроллера представления одновременно (представление первого контроллера представления только что запущено, и вы, возможно, пытаетесь представить второй контроллер представления).

Вы должны переместить свой код (для представления/навигации контроллера представления) в viewDidAppear. Ваш основной вид существующего контроллера представления (откуда вы представляете новый контроллер представления) не готов/загружен.

Вы должны переместить его на viewDidAppear.


Вот пример кода:

Свифт 4

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)

    // instantiate your view controller either using storyboard or class or any other way....
    if let newVC = self.storyboard?.instantiateViewController(withIdentifier: "NewViewController") as? NewViewController {
         self.present(newVC, animated: true, completion: nil)
    }
}

В вашем случае/коде решение:

override func viewDidLoad() {
    super.viewDidLoad()

     // Move your code from here (viewDidLoad) to viewDidAppear

}

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)

    // to check whether the user has already logged in or not
    Auth.auth().addStateDidChangeListener { (auth, user) in
        if user == nil {
            let login = self.storyboard?.instantiateViewController(withIdentifier: "login") as! LoginVC
            self.present(login, animated: true, completion: nil)
        }
    }

    print("user enter homeVC")

}

Посмотрите на разницу между жизненным циклом обоих контроллеров представления.

viewDidLoad

Этот метод вызывается после того, как контроллер представления загрузил свою иерархию представлений в память. Этот метод вызывается независимо от того, была ли иерархия представлений загружена из файла пера или создана программно в методе loadView(). Обычно вы переопределяете этот метод, чтобы выполнить дополнительную инициализацию представлений, которые были загружены из файлов пера.
Подробнее о: viewDidLoad

viewDidAppear

Уведомляет контроллер представления о том, что его представление было добавлено в иерархию представлений.
Подробнее о: viewDidAppear

person Krunal    schedule 18.01.2018

На данный момент в вашем коде представление контроллера представления было только создано, но не добавлено ни в какую иерархию представлений. Если вы хотите как можно скорее представить этот контроллер представления, вы должны сделать это в viewDidAppear, чтобы быть максимально безопасным.

person Muhammad Ahmad    schedule 19.07.2020