Swift/iOS:加载视图控制器后 IBOutlet nil
Swift/iOS: IBOutlet nil after loading view controller
我正在构建一个应用程序(在 XCode 8.2.1 中),其中一些对象显示在 2D 板上,当用户点击这些对象之一时,一些信息应该显示为样式化的模态信息框。我的设计是将信息写在一个单独的视图控制器中,我会在需要时显示它。
我为第二个视图控制器设计了一个基本存根,并在界面生成器中为其添加了一个标签。然后我将此标签链接到我的自定义 VC class:
class InfoViewController: UIViewController {
@IBOutlet weak var info: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
}
func displayInfo() {
info.attributedText = NSAttributedString(string: "abc")
}
}
但是,当我测试我的应用程序并点击对象时,info
字段是 nil
即使在我自定义 VC [=43] 的 viewDidLoad()
方法中也是如此=].我显示 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()
的引用,它实例化了独立于任何故事板场景的视图控制器。你想使用 instantiateViewController
:
let infoViewController = storyboard?.instantiateViewController(withIdentifier: "Info") as! InfoViewController
infoViewController.modalPresentationStyle = .overCurrentContext
present(infoViewController, animated: true) {
infoViewController.displayInfo()
}
一些注意事项:
这假设 (a) 您已经为情节提要中的场景指定了 "storyboard id"; (b) 您已将该场景的基础 class 设置为 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
并添加了名为 info
的 String
属性。这往往是惯例,插座带有一些后缀,指示控件的类型,而模型对象,如 String
属性,没有后缀。 (您只需确保在 IB 的连接检查器中删除旧插座,这样您就不会遇到这些 属性 名称更改的问题。)
无论如何,你可以这样做:
let infoViewController = storyboard?.instantiateViewController(withIdentifier: "Info") as! InfoViewController
infoViewController.info = "abc"
infoViewController.modalPresentationStyle = .overCurrentContext
present(infoViewController, animated: true, completion: nil)
关键是不要尝试在实例化场景后立即更新场景的出口,但要确保将其推迟到调用 viewDidLoad
之后。
我换了
let vc = CCDetailViewController()
与
let vc = self.storyboard?.instantiateViewController(withIdentifier: "CCDetailViewController")
终于
self.present(vc!, animated: true, completion: nil)
现在可以使用了...
在我的例子中,我为同一个 class 创建了新的视图控制器。最后在故事板中有两个视图控制器,但指的是相同的 class。删除旧视图控制器后,一切正常。
希望对大家有所帮助。
我正在构建一个应用程序(在 XCode 8.2.1 中),其中一些对象显示在 2D 板上,当用户点击这些对象之一时,一些信息应该显示为样式化的模态信息框。我的设计是将信息写在一个单独的视图控制器中,我会在需要时显示它。
我为第二个视图控制器设计了一个基本存根,并在界面生成器中为其添加了一个标签。然后我将此标签链接到我的自定义 VC class:
class InfoViewController: UIViewController {
@IBOutlet weak var info: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
}
func displayInfo() {
info.attributedText = NSAttributedString(string: "abc")
}
}
但是,当我测试我的应用程序并点击对象时,info
字段是 nil
即使在我自定义 VC [=43] 的 viewDidLoad()
方法中也是如此=].我显示 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()
的引用,它实例化了独立于任何故事板场景的视图控制器。你想使用 instantiateViewController
:
let infoViewController = storyboard?.instantiateViewController(withIdentifier: "Info") as! InfoViewController
infoViewController.modalPresentationStyle = .overCurrentContext
present(infoViewController, animated: true) {
infoViewController.displayInfo()
}
一些注意事项:
这假设 (a) 您已经为情节提要中的场景指定了 "storyboard id"; (b) 您已将该场景的基础 class 设置为
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
并添加了名为 info
的 String
属性。这往往是惯例,插座带有一些后缀,指示控件的类型,而模型对象,如 String
属性,没有后缀。 (您只需确保在 IB 的连接检查器中删除旧插座,这样您就不会遇到这些 属性 名称更改的问题。)
无论如何,你可以这样做:
let infoViewController = storyboard?.instantiateViewController(withIdentifier: "Info") as! InfoViewController
infoViewController.info = "abc"
infoViewController.modalPresentationStyle = .overCurrentContext
present(infoViewController, animated: true, completion: nil)
关键是不要尝试在实例化场景后立即更新场景的出口,但要确保将其推迟到调用 viewDidLoad
之后。
我换了
let vc = CCDetailViewController()
与
let vc = self.storyboard?.instantiateViewController(withIdentifier: "CCDetailViewController")
终于
self.present(vc!, animated: true, completion: nil)
现在可以使用了...
在我的例子中,我为同一个 class 创建了新的视图控制器。最后在故事板中有两个视图控制器,但指的是相同的 class。删除旧视图控制器后,一切正常。
希望对大家有所帮助。