引用项目在 viewDidLoad 中安全地初始化

Referencing item's initialized in viewDidLoad safely

我 运行 本周早些时候遇到了一个奇怪的错误,想跟进以了解如何防止问题的根本原因。

取下面的代码。

//*****************************
//MAINVIEWCONTROLLER CLASS CODE
//*****************************

//Some event happens that triggers me to want to load up TestViewController.
func showViewController(){
    var testController = TestViewController()
    testController.someMethod("Test1")

    self.navigationController?.pushViewController(testController, animated: true)
}

//*****************************
//TESTVIEWCONTROLLER CLASS CODE
//*****************************
testView:TestView!   

override func viewDidLoad(){
    super.viewDidLoad()
    testView = TestView()
    ...
}    

func someMethod(someData:String){
    testView.name = someData         //AppCrashes here because testView might be nil.
    ...
}

所以 someMethodTestViewController 有机会通过并创建 testView 之前就被解雇了。然后我得到一个 cannot unwrap an optional value because testView is nil 并且我正在访问它上面的 属性 。

Whats st运行ge 是我的应用程序 运行 可能在 6 个不同的地方做这件事,5/6 工作得很好,但 1/6 现在给我这个错误。我猜是因为 viewDidLoad 没有被 gua运行teed 立即触发或在 someMethod 执行之前完成,但是为什么这在所有 6 个用例中都没有发生.

所以我的主要问题是:

  1. 为什么会发生此崩溃?
  2. 避免它的最佳做法是什么。

谢谢!深思熟虑的答案将一如既往地获得投票!让我知道是否有更多信息会有所帮助。

viewDidLoad 在 ViewController 完成加载准备显示时调用,例如当发生转折或涉及礼物时。

正如所写,您的代码甚至不应该编译,因为 testView 是可选的,但您有两个选择。使用可选项(在这种情况下,如果在 viewDidLoad 之后未调用,视图可能无法获取信息,但它不会崩溃)或存储传递的信息并在 viewDidLoad 或 viewWillAppear 中更新您的视图。

您可能需要注意的是 viewIfLoaded

您可以强制使用 viewDidLoad 方法:

var testViewController = TestViewController() _ = testViewController.view testViewController.someMethod("Test")

初始化 ViewController 不会自动调用 viewDidLoad

基本上从不 运行 从源控制器调用的目标控制器中涉及 UI 元素的代码。创建一个属性,在源控制器中设置它并将值赋给目标控制器viewDidLoad()中的UI元素,例如:

//*****************************
//MAINVIEWCONTROLLER CLASS CODE
//*****************************

//Some event happens that triggers me to want to load up TestViewController.
func showViewController(){
    var testController = TestViewController()
    testController.someData = "Test1"

    self.navigationController?.pushViewController(testController, animated: true)
}

//*****************************
//TESTVIEWCONTROLLER CLASS CODE
//*****************************
testView:TestView!

var someData = ""   

override func viewDidLoad(){
    super.viewDidLoad()
    testView = TestView()
    testView.name = someData
    ...
}