如何在Swift中为UIViewController子类创建自定义初始化程序?

时间:2014-11-14 04:40:14

标签: swift uiviewcontroller initialization

如果之前有人问过这个道歉,我已经搜索了很多,而且当事情不同时,许多答案来自早期的Swift beta。我似乎无法找到明确的答案。

我想继承UIViewController并拥有自定义初始化程序,以便我可以轻松地在代码中进行设置。我在Swift中遇到这个问题。

我想要一个init()函数,我可以使用该函数传递特定的NSURL然后我将使用视图控制器。在我看来,它看起来像init(withImageURL: NSURL)。如果我添加该功能,则会要求我添加init(coder: NSCoder)功能。

我相信这是因为它在超类中标有required关键字?所以我必须在子类中做到这一点?我添加它:

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

现在怎样?我的特殊初始值设定项是convenience吗?指定的一个?我打电话给超级初始化器吗?来自同一个类的初始化器?

如何将我的特殊初始值设定项添加到UIViewController子类?

5 个答案:

答案 0 :(得分:121)

class ViewController: UIViewController {

    var imageURL: NSURL?

    // this is a convenient way to create this view controller without a imageURL
    convenience init() {
        self.init(imageURL: nil)
    }

    init(imageURL: NSURL?) {
        self.imageURL = imageURL
        super.init(nibName: nil, bundle: nil)
    }

    // if this view controller is loaded from a storyboard, imageURL will be nil

    /* Xcode 6
    required init(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }
    */

    // Xcode 7 & 8
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }
}

答案 1 :(得分:5)

  

便利初始化程序是次要的,支持a的初始化程序   类。您可以定义一个便捷初始化程序来调用指定的   初始化程序与便捷初始化程序所在的类相同   一些指定的初始化程序的参数设置为默认值。   您还可以定义一个便利初始化程序来创建一个实例   特定用例或输入值类型的类。

记录在案here

答案 2 :(得分:3)

对于那些用代码编写UI的人

class Your_ViewController : UIViewController {

    let your_property : String

    init(your_property: String) {
        self.your_property = your_property
        super.init(nibName: nil, bundle: nil)
    }

    override func viewDidLoad() {
        super.viewDidLoad()

    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) is not supported")
    }
}

答案 3 :(得分:3)

这与其他答案非常相似,但有一些解释。被接受的答案具有误导性,因为它的属性是可选的,并且不会暴露init?(coder: NSCoder)必须初始化每个属性以及唯一的事实。解决该问题的方法是使用fatalError()。话虽这么说,您可以通过将属性设置为可选属性来摆脱困境,但这并不能真正回答OP的问题。

// Think more of a OnlyNibOrProgrammatic_NOTStoryboardViewController
class ViewController: UIViewController {

    let name: String

    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .blue
    }

    // I don't have a nib. It's all through my code.
    init(name: String) {
        self.name = name

        super.init(nibName: nil, bundle: nil)
    }

    // I have a nib. I'd like to use my nib and also initialze the `name` property
    init(name: String, nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle? ) {
        self.name = name
        super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
    }

    // when you do storyboard.instantiateViewController(withIdentifier: "ViewController")
    // The SYSTEM will never call this!
    // it wants to call the required initializer!

    init?(name: String, coder aDecoder: NSCoder) {
        self.name = "name"
        super.init(coder: aDecoder)
    }

    // when you do storyboard.instantiateViewController(withIdentifier: "ViewController")
    // The SYSTEM WILL call this!
    // because this is its required initializer!
    // but what are you going to do for your `name` property?!
    // are you just going to do `self.name = "default Name" just to make it compile?!
    // Since you can't do anything then it's just best to leave it as `fatalError()`
    required init?(coder aDecoder: NSCoder) {
        fatalError("I WILL NEVER instantiate through storyboard! It's impossible to initialize super.init?(coder aDecoder: NSCoder) with any other parameter")
    }
}

基本上,您必须从情节提要中ABANDON加载它。为什么?

因为当您调用viewController storyboard.instantiateViewController(withIdentifier: "viewController")时,SYSTEM将执行其工作并调用

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

您永远不能将该调用重定向到另一个init方法。但是,对于以编程方式创建的viewController或笔尖创建的viewControllers,您可以如上所示重定向该调用。

答案 4 :(得分:0)

例如,如果您需要弹出框的自定义初始化,可以使用以下方法:

创建一个自定义init,它使用带有nibName和bundle的超级init,然后访问view属性以强制加载视图层次结构。

然后在viewDidLoad函数中,您可以使用初始化中传递的参数配置视图。

import UIKit

struct Player {
    let name: String
    let age: Int
}

class VC: UIViewController {


@IBOutlet weak var playerName: UILabel!

let player: Player

init(player: Player) {
    self.player = player
    super.init(nibName: "VC", bundle: Bundle.main)
    if let view = view, view.isHidden {}
}

override func viewDidLoad() {
    super.viewDidLoad()
    configure()
}

func configure() {
    playerName.text = player.name + "\(player.age)"
}
}

func showPlayerVC() {
    let foo = Player(name: "bar", age: 666)
    let vc = VC(player: foo)
    present(vc, animated: true, completion: nil)
}