如果之前有人问过这个道歉,我已经搜索了很多,而且当事情不同时,许多答案来自早期的Swift beta。我似乎无法找到明确的答案。
我想继承UIViewController
并拥有自定义初始化程序,以便我可以轻松地在代码中进行设置。我在Swift中遇到这个问题。
我想要一个init()
函数,我可以使用该函数传递特定的NSURL
然后我将使用视图控制器。在我看来,它看起来像init(withImageURL: NSURL)
。如果我添加该功能,则会要求我添加init(coder: NSCoder)
功能。
我相信这是因为它在超类中标有required
关键字?所以我必须在子类中做到这一点?我添加它:
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
现在怎样?我的特殊初始值设定项是convenience
吗?指定的一个?我打电话给超级初始化器吗?来自同一个类的初始化器?
如何将我的特殊初始值设定项添加到UIViewController
子类?
答案 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)
}