在Swift中用UIViewController的自定义初始化,并在故事板中设置界面

我有问题为UIViewController的子类编写自定义的init,基本上我想通过viewController的init方法传递依赖,而不是像viewControllerB.property = value那样直接设置属性

所以我为我的viewController做了一个自定义的init,并调用超级指定的init

init(meme: Meme?) {
        self.meme = meme
        super.init(nibName: nil, bundle: nil)
    }

视图控制器界面驻留在故事板中,我也使自定义类的界面成为我的视图控制器。 即使你没有在这个方法中做任何事情,Swift也需要调用这个init方法。 否则,编译器会抱怨...

required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }

问题是当我尝试使用MyViewController(meme: meme)调用我的自定义init时,它根本没有在我的viewController中初始化属性......

我试图调试,我发现在我的viewController, init(coder aDecoder: NSCoder)被调用,然后我的自定义init被调用。 但是,这两个init方法返回不同的self内存地址。

我怀疑我的viewController的init有什么问题,并且它会一直使用init?(coder aDecoder: NSCoder)返回self ,它没有实现。

有谁知道如何正确地为你的viewController自定义init? 注意:我的viewController的界面是在storyboard中设置的

这里是我的viewController代码:

class MemeDetailVC : UIViewController {

    var meme : Meme!

    @IBOutlet weak var editedImage: UIImageView!

    // TODO: incorrect init
    init(meme: Meme?) {
        self.meme = meme
        super.init(nibName: nil, bundle: nil)
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }

    override func viewDidLoad() {
        /// setup nav title
        title = "Detail Meme"

        super.viewDidLoad()
    }

    override func viewWillAppear(animated: Bool) {
        super.viewWillAppear(animated)
        editedImage = UIImageView(image: meme.editedImage)
    }

}

使用init?(coder aDecoder: NSCoder)是如何设计故事板来初始化控制器的时候,当你从故事板初始化时,你不能使用自定义初始化器。 但是,有办法将数据发送到UIViewController

你的视图控制器的名字中有detail的内容,所以我想你是从另一个控制器那里得到的。 在这种情况下,您可以使用prepareForSegue方法将数据发送到细节(这是Swift 3):

override func prepare(for segue: UIStoryboardSegue, sender: AnyObject?) {
    if segue.identifier == "identifier" {
        if let controller = segue.destinationViewController as? MemeDetailVC {
            controller.meme = "Meme"
        }
    }
}

我只是使用String类型的属性而不是Meme来进行测试。 此外,请确保您传递了正确的segue标识符( "identifier"只是一个占位符)。


正如在上面的答案中指定的那样,您不能同时使用自定义init方法和storyboard。 但是您仍然可以使用静态方法从故事板实例化ViewController并对其执行其他设置。 它看起来像这样:

class MemeDetailVC : UIViewController {

    var meme : Meme!

    static func makeMemeDetailVC(meme: Meme) -> MemeDetailVC {
        let newViewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewControllerWithIdentifier("IdentifierOfYouViewController") as! MemeDetailVC

        newViewController.meme = meme

        return newViewController
    }
}

不要忘记在Storyboard中指定IdentifierOfYouViewController作为视图控制器标识符。 您可能还需要在上面的代码中更改故事板的名称。


我已经做到这一点的一种方法是使用便利的初始化程序。

class MemeDetailVC : UIViewController {

    convenience init(meme: Meme) {
        self.init()
        self.meme = meme
    }
}

然后你用let memeDetailVC = MemeDetailVC(theMeme)初始化你的MemeDetailVC,

关于初始化器的Apple文档相当不错,但我个人最喜欢的是Ray Wenderlich:初始化深入教程系列,它应该给你很多关于各种初始化选项的解释/例子和“正确”的做法。


编辑 :虽然您可以在自定义视图控制器上使用便利初始值设定项,但每个人在说明从故事板或通过故事板渐变初始化时都无法使用自定义初始值设定项时是正确的。

如果你的界面是在storyboard中设置的,并且你完全以编程的方式创建控制器,那么一个方便的初始化器可能是最简单的方法来做你想做的事情,因为你不必处理所需的init NSCoder(我仍然不太明白)。

如果你通过故事板获得视图控制器,那么你需要遵循@Caleb Kleveter的回答,并将视图控制器转换为你想要的子类,然后手动设置属性。

链接地址: http://www.djcxy.com/p/87737.html

上一篇: Custom init for UIViewController in Swift with interface setup in storyboard

下一篇: Implementing programatically UIView over a UIViewController