![](/img/trans.png)
[英]How do I initialize a custom ViewController when there's no Storyboard?
[英]How to initialize ViewController from storyboard using it's Coder
我意识到这可能很难实现,但我希望能够直接使用init(coder: NSCoder)
function 从storyboard
初始化ViewControllers
。 我的意思是不使用storyboard.instantiateViewController(identifier: coder: )
- 我知道我可以使用它,但这是我想跳过的。 相反,我更愿意在ViewController
中有一个像这样的 init: init(viewModel: ViewModel)
并使用这个 init 从storyboard
初始化这个ViewController
。 在这个 init 中,我想象有一些机制可以打开我的storyboard
,并以某种方式提取它的编码器,这样我就可以写:
static let storyboard = UIStoryboard(named: "Game")
private let viewModel: ViewModel
init(viewModel: ViewModel) {
self.viewModel = viewModel
let identifier = String(describing: Self.self)
let coder: NSCoder = Self.storyboard.somehowGetTheCoderForViewController(withId: identifier)
super.init(coder: coder)
}
问题是如何以我能够从中获取特定 ViewController 的编码器的方式读取 storyboard。 再次 - 我知道这可以通过使用这样的东西来解决
storyboard.instantiateViewController(identifier: String(describing: Self.self)) { coder in
Self.init(coder: coder, viewModel: viewModel)
}
但是我正在寻找一种不使用instantiateViewController
的方法,而只是能够获得coder
,这样以后我就可以像这样initiate
VC 了:
let viewController = ViewContorller(viewModel: viewModel)
所以问题是如何解压storyboard
,并为一些ViewController
检索coder
object 。
你不应该这样做。
正如init(nibName:bundle:)
的文档所说:
这是这个 class 的指定初始化程序。当使用 storyboard 定义视图 controller 及其关联视图时,您永远不会直接初始化视图 controller class。 相反,视图控制器由 storyboard 实例化,或者在触发 segue 时自动实例化,或者在您的应用程序调用 storyboard object 的
instantiateViewController(withIdentifier:)
方法时以编程方式实例化。
使用初始化程序初始化 VC 时,您应该使用该初始化程序,而不是init(coder:)
。 如果你使用故事板,那么你应该使用instantiateViewController
,或者使用 segues 来获取新的 VC。
所以要实现这个语法:
let viewController = ViewContorller(viewModel: viewModel)
您可以将您的 VC 放入 xib 文件中,然后执行以下操作:
init(viewModel: ViewModel) {
self.viewModel = viewModel
let identifier = String(describing: Self.self)
let coder: NSCoder = Self.storyboard.somehowGetTheCoderForViewController(withId: identifier)
super.init(nibName: String(describing: Self.self), bundle: nil)
}
如果你必须使用故事板,那么你不能使用初始化语法来初始化 VC。 您可以改用工厂方法,例如:
let viewController = ViewContorller.from(viewModel: viewModel)
并使用UIStoryboard.instantiateViewController
实现它。
这就是初始化程序instantiateViewController(identifier:creator:)
存在的原因。
https://developer.apple.com/documentation/uikit/uistoryboard/3213989-instantiateviewcontroller
您收到coder
并使用它来调用自定义初始化器,该初始化器本身调用coder
初始化器,但也执行其他自定义初始化。
为了说明这一点,假设我们有一个 ViewController class,它有一个message
字符串属性,当视图出现时,它会在 UILabel 中呈现给用户。 所以我们给了 ViewController 一个init(coder:message:)
初始化器:
class ViewController: UIViewController {
@IBOutlet var lab : UILabel!
var message: String = ""
convenience init(coder:NSCoder, message:String) {
self.init(coder:coder)!
self.message = message
}
override func viewDidLoad() {
super.viewDidLoad()
self.lab.text = self.message
}
}
然而,任其自生自灭,运行时永远不会调用我们的init(coder:message:)
初始化程序; 它对此一无所知! 运行时知道从 storyboard 实例化视图 controller 的唯一方法是调用init(coder:)
。 但是当我们从 storyboard 实例化视图 controller 时,我们可以调用init(coder:message:)
。
假设这是故事板的初始视图 controller,我们在启动时在场景委托中调用它:
func scene(_ scene: UIScene,
willConnectTo session: UISceneSession,
options connectionOptions: UIScene.ConnectionOptions) {
guard let scene = (scene as? UIWindowScene) else { return }
let message = "Howdy, world!" // or whatever
self.window = UIWindow(windowScene: scene)
let sb = UIStoryboard(name: "Main", bundle: nil)
self.window?.rootViewController = sb.instantiateInitialViewController {
return ViewController(coder: $0, message: message)
}
self.window?.makeKeyAndVisible()
}
我们调用instantiateViewController(identifier:creator:)
和creator:
function 调用init(coder:message:)
—— 反过来调用init(coder:)
。 因此我们对creator:
function 的使用是合法的,并且视图正确显示。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.