xcode Swift/iOS:加载视图控制器后 IBOutlet 为零

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/41453042/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-15 09:42:10  来源:igfitidea点击:

Swift/iOS: IBOutlet nil after loading view controller

iosswiftxcodeuiviewcontrollerviewdidload

提问by David

I'm building an app (in XCode 8.2.1) where some objects are displayed on a 2D board, and when the user taps one of these objects some info should be displayed about it as a styled modal info box. My design is to have the info written in a separate view controller, which I would display when needed.

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

I've designed a basic stub for the second view controller and added a single label to it in the interface builder. Then I've ctrl-linked this label to my custom VC class:

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

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

However, when I test my app and tap the object, the infofield is nileven in the viewDidLoad()method of my custom VC class. The way I'm displaying my VC is as follows:

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

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

(Note: In the end I will have only one single instance of InfoViewControllerbut this is just for testing. I don't expect having a global instance would make any difference?)

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

As I said, be it inside the viewDidLoad()method or in the displayInfo()method, infois always nil, such that setting its attributedStringattribute crashes the app. Thinking the presentmethod might be called asynchronously, I've tried calling displayInfo()from inside viewDidLoad(), but that didn't make any difference.

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

Can anyone tell my what I've forgotten that would allow my IBOutletfrom being properly initialized properly?

谁能告诉我我忘记了什么可以让我IBOutlet正确初始化?

Thanks!

谢谢!

David

大卫

回答by Rob

The problem is the reference to InfoViewController(), which instantiates the view controller independent of any storyboard scene. You want to use instantiateViewController:

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

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

A couple of notes:

一些注意事项:

  • This assumes that (a) you've given the scene in the storyboard a "storyboard id"; (b) you've set the base class for that scene to InfoViewController.

  • Note, I called displayInfoin the completion handler of presentbecause you probably don't want that called until the scene has been presented and the outlets have been hooked up.

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

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



Alternatively, you can update non-outlet properties of the InfoViewControllerimmediately after instantiating it and then have its viewDidLoadtake those properties and update the outlets, e.g.:

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

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

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

Note, I changed the @IBOutletname to be infoLabeland added the Stringproperty called info. That tends to be the convention, that outlets bear some suffix indicating the type of control, and model objects, like the Stringproperty, are without the suffix. (You'll just want to make sure you remove that old outlet in the connections inspector in IB so that you don't have problems with these property name changes.)

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

Anyway, you can then do:

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

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

The key point is don't try to update outlets of the scene immediately after instantiating it, but make sure that this is deferred until after viewDidLoadwas called.

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

回答by iOS Lifee

I Replaced

我替换了

let vc = CCDetailViewController()

With

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

Finally

最后

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

Now It Works...

现在它有效...

回答by Suresh Vutukuru

In my case, I had created new view controller for the same class. Which had ended up with two view controllers in storyboard, but referring to the same class. After deleting old view controller, everything worked fine.

就我而言,我为同一个类创建了新的视图控制器。最终在故事板中有两个视图控制器,但指的是同一个类。删除旧的视图控制器后,一切正常。

Hope it helps to someone.

希望它对某人有所帮助。