IBOutlet 变量在我尝试访问它们时返回 nil。错误:线程 1:致命错误:在展开可选值时意外发现 nil

Posted

技术标签:

【中文标题】IBOutlet 变量在我尝试访问它们时返回 nil。错误:线程 1:致命错误:在展开可选值时意外发现 nil【英文标题】:IBOutlet variables return nil when I try to access them. Error: Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value 【发布时间】:2019-04-05 13:49:21 【问题描述】:

我有一个实现MGLMapViewDelegateUIViewController。我试图在顶部放置一个导航栏,带有两个按钮。

我无法看到我的按钮或导航栏,因此我尝试按照this post 的建议在viewDidLoadFunction() 中使用view.bringSubviewToFront() 函数

当我这样做时,我收到了错误

错误:线程 1:致命错误:在展开可选值时意外发现 nil

我不明白IBOutlet 变量怎么可能为零,我以为它们被分配给情节提要按钮


我的 ViewController 类(至少我认为重要的部分)

class ViewController: UIViewController, MGLMapViewDelegate 

...

var mapView: MGLMapView?
@IBOutlet var navBar: UINavigationBar!
@IBOutlet var signOutButton: UIButton!
@IBOutlet var newPostButton: UIButton!

...

override func viewDidLoad() 
            super.viewDidLoad()

    self.mapView = MGLMapView(frame: view.bounds, styleURL: MGLStyle.lightStyleURL)

    ...

        view.addSubview(self.mapView!)

        view.addSubview(navBar)
        view.addSubview(signOutButton)
        view.addSubview(newPostButton)
        //Make the navBar and Buttons visible
        view.bringSubviewToFront(self.navBar)
        view.bringSubviewToFront(self.signOutButton)
        view.bringSubviewToFront(self.newPostButton)

        ...


...

@objc func handleLogout() 
     let loginController = SignInViewController()

     do 
          try Auth.auth().signOut()
       catch let logoutError 
          print(logoutError)
      

      present(loginController, animated: true, completion: nil)
  


我认为可能很重要的故事板的一些屏幕截图

I've tried placing this in my view controller right after super.viewDidLoad()

self.storyboard?.instantiateViewController(withIdentifier: "mainViewController") as! ViewController

我尝试将视图带到地图视图的前面而不是主视图

self.mapView.bringViewToFront(navBar)

I've tried placing the code inside functions like awakeFromNib and viewDidLayoutSubviews

    override func awakeFromNib() 
        super.awakeFromNib()

        //Make the navBar and Buttons visible
        self.mapView!.bringSubviewToFront(self.navBar)
        self.mapView!.bringSubviewToFront(self.signOutButton)
        self.mapView!.bringSubviewToFront(self.newPostButton)

    

【问题讨论】:

你检查你的 mapView 是否为 nil 吗? 为什么 view.addSubview(signOutButton) 已经在故事板中了? @Teetz 我没有,但它只发生在 view.addSubview 上,它不会是 mapView。不过我会试试的 @Alastar 这是确保按钮在视图中的调试尝试,我第一次尝试时没有出现。如果您认为这样会更清楚或更好,我可以将其删除? @Jacob - 您的项目中是否有多个故事板?如果是这样,您是否可以将主界面设置为不同的故事板,使用不同的视图控制器? 【参考方案1】:

从您的 cmets 中,我了解到您错误地实例化了控制器。

let mainController = ViewController(). // Wrong

这只会实例化 ViewController 而不是故事板中的任何对象。

使用以下代码从情节提要中实例化视图控制器。

    if let vc = self.storyboard?.instantiateViewController(withIdentifier: "mainViewController") as? ViewController 
        //Set any data if required, then present
        self.present(vc, animated: true, completion: nil)
    

如果您使用多个故事板,

 let storyboard = UIStoryboard(name: "Main", bundle: nil)
 if let vc = storyboard.instantiateViewController(withIdentifier: "mainViewController") as? ViewController 
        self.present(vc, animated: true, completion: nil)
   

【讨论】:

我试过了,但什么也没发生,所以我尝试了dump(self.storyboard),结果为零。我觉得值得一提的是,调用 self.storyboard 的类不是来自故事板。这是我用代码编写的视图控制器。在我的故事板中为此类创建视图控制器窗格的最简单方法是什么? 我的登录情节提要场景转到主视图,但它也转到链接到主视图的其他一些视图控制器,如果让您感到困惑,非常抱歉 所以我使用了if let vc = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "mainViewController") as? ViewController ,它成功了。如果您遵循良好的做法,您的答案就是这样做的方法。也许添加一个注释,说明如果视图位于不同的故事板上,您可以调用UIStoryboard(name: "Main", bundle: nil).instantiateViewController?这取决于你,我相信有人会很高兴你这样做。 是的,我做到了..!

以上是关于IBOutlet 变量在我尝试访问它们时返回 nil。错误:线程 1:致命错误:在展开可选值时意外发现 nil的主要内容,如果未能解决你的问题,请参考以下文章

从另一个类访问 IBOutlet

在模态视图的父视图中访问 IBOutlet

从 NIB 加载后 IBOutlet 实例为(空)

如何使用 IBOutlet 子类化变量?

GSP:检查模型(变量)是不是为空不工作

无法在 Interface Builder 中连接 IBOutlet