【问题标题】:Swift/iOS: IBOutlet nil after loading view controllerSwift/iOS:加载视图控制器后 IBOutlet nil
【发布时间】:2017-05-18 02:35:22
【问题描述】:

我正在构建一个应用程序(在 XCode 8.2.1 中),其中一些对象显示在 2D 板上,当用户点击其中一个对象时,应该将一些关于它的信息显示为样式化的模态信息框。我的设计是将信息写在一个单独的视图控制器中,我会在需要时显示它。

我为第二个视图控制器设计了一个基本存根,并在界面构建器中为其添加了一个标签。然后我将此标签 ctrl 链接到我的自定义 VC 类:

class InfoViewController: UIViewController {
    @IBOutlet weak var info: UILabel!
    override func viewDidLoad() {
        super.viewDidLoad()
    }
    func displayInfo() {
        info.attributedText = NSAttributedString(string: "abc")
    }
}

但是,当我测试我的应用程序并点击对象时,info 字段即使在我的自定义 VC 类的 viewDidLoad() 方法中也是 nil。我展示我的VC的方式如下:

let infoViewController = InfoViewController()
infoViewController.modalPresentationStyle = .overCurrentContext
self.present(infoViewController, animated: true, completion: nil)
infoViewController.displayInfo()

(注意:最后我将只有一个InfoViewController 的实例,但这只是为了测试。我不希望拥有一个全局实例会有什么不同?)

正如我所说,无论是在viewDidLoad() 方法中还是在displayInfo() 方法中,info 始终是nil,因此设置其attributedString 属性会使应用程序崩溃。考虑到present 方法可能被异步调用,我尝试从viewDidLoad() 内部调用displayInfo(),但这没有任何区别。

谁能告诉我我忘记了什么会让我的IBOutlet 无法正确初始化?

谢谢!

大卫

【问题讨论】:

  • 你使用故事板吗?如果是,那么我假设您应该从情节提要中获取InfoViewController,而不是通过创建新实例...

标签: ios swift xcode uiviewcontroller viewdidload


【解决方案1】:

问题是对InfoViewController() 的引用,它实例化了独立于任何故事板场景的视图控制器。你想用instantiateViewController:

let infoViewController = storyboard?.instantiateViewController(withIdentifier: "Info") as! InfoViewController
infoViewController.modalPresentationStyle = .overCurrentContext
present(infoViewController, animated: true) {
    infoViewController.displayInfo()
}

几点说明:

  • 这假设 (a) 您已为情节提要中的场景指定了“情节提要 ID”; (b) 您已将该场景的基类设置为 InfoViewController

  • 注意,我在 present 的完成处理程序中调用了 displayInfo,因为您可能不希望在呈现场景并且连接出口之前调用它。

    李>

或者,您可以在实例化 InfoViewController 后立即更新其非出口属性,然后让其 viewDidLoad 获取这些属性并更新出口,例如:

class InfoViewController: UIViewController {
    var info: String!
    @IBOutlet weak var infoLabel: UILabel!

    override func viewDidLoad() {
        super.viewDidLoad()
        infoLabel.attributedText = NSAttributedString(string: info)
    }
}

注意,我将 @IBOutlet 名称更改为 infoLabel 并添加了名为 infoString 属性。这往往是惯例,出口带有一些后缀来指示控件的类型,而模型对象(如String 属性)则没有后缀。 (您只需要确保在 IB 的连接检查器中删除旧插座,这样您就不会遇到这些属性名称更改的问题。)

无论如何,你可以这样做:

let infoViewController = storyboard?.instantiateViewController(withIdentifier: "Info") as! InfoViewController
infoViewController.info = "abc"
infoViewController.modalPresentationStyle = .overCurrentContext
present(infoViewController, animated: true, completion: nil)

关键点是不要在实例化后立即尝试更新场景的出口,但要确保将其推迟到调用 viewDidLoad 之后。

【讨论】:

  • 非常感谢!我认为调用self.present 将执行与情节提要的必要链接。
【解决方案2】:

我换了

let vc = CCDetailViewController()

let vc = self.storyboard?.instantiateViewController(withIdentifier: "CCDetailViewController")

终于

self.present(vc!, animated: true, completion: nil)

现在可以了...

【讨论】:

    【解决方案3】:

    在我的例子中,我为同一个类创建了新的视图控制器。最终在情节提要中有两个视图控制器,但指的是同一个类。删除旧视图控制器后,一切正常。

    希望对某人有所帮助。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-09-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-05-10
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多