简体   繁体   English

如何使用它的 Coder 从 storyboard 初始化 ViewController

[英]How to initialize ViewController from storyboard using it's Coder

I realize that this might be difficult to achieve, but I would like to be able to initialize ViewControllers from storyboard using init(coder: NSCoder) function directly.我意识到这可能很难实现,但我希望能够直接使用init(coder: NSCoder) function 从storyboard初始化ViewControllers I mean not using storyboard.instantiateViewController(identifier: coder: ) - I know I could use this, but this is what I would like to skip.我的意思是不使用storyboard.instantiateViewController(identifier: coder: ) - 我知道我可以使用它,但这是我想跳过的。 Instead I would prefer to have a init in ViewController like this: init(viewModel: ViewModel) and use this init to initialize this ViewController from the storyboard .相反,我更愿意在ViewController中有一个像这样的 init: init(viewModel: ViewModel)并使用这个 init 从storyboard初始化这个ViewController Inside this init I imagine having some mechanism that would open my storyboard , and extracted it's coder somehow, so that I could write:在这个 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)
}

Problem is how to read storyboard in such a way that I was able to get the coder of particular ViewController from it.问题是如何以我能够从中获取特定 ViewController 的编码器的方式读取 storyboard。 Again - I know this can be solved by using something like this再次 - 我知道这可以通过使用这样的东西来解决

storyboard.instantiateViewController(identifier: String(describing: Self.self)) { coder in
    Self.init(coder: coder, viewModel: viewModel)
}

But Im looking for a way to not use instantiateViewController , and just be able to get the coder , so that later I could just initiate VC like this:但是我正在寻找一种不使用instantiateViewController的方法,而只是能够获得coder ,这样以后我就可以像这样initiate VC 了:

let viewController = ViewContorller(viewModel: viewModel)

So the question is how to unpack storyboard , and retrieve coder object for some ViewController .所以问题是如何解压storyboard ,并为一些ViewController检索coder object 。

You are not supposed to do this.你不应该这样做。

As the documentation of init(nibName:bundle:) says:正如init(nibName:bundle:)的文档所说:

This is the designated initializer for this class. When using a storyboard to define your view controller and its associated views, you never initialize your view controller class directly.这是这个 class 的指定初始化程序。当使用 storyboard 定义视图 controller 及其关联视图时,您永远不会直接初始化视图 controller class。 Instead, view controllers are instantiated by the storyboard either automatically when a segue is triggered or programmatically when your app calls the instantiateViewController(withIdentifier:) method of a storyboard object.相反,视图控制器由 storyboard 实例化,或者在触发 segue 时自动实例化,或者在您的应用程序调用 storyboard object 的instantiateViewController(withIdentifier:)方法时以编程方式实例化。

When initialising a VC using an initialiser, that initialiser is what you should use, not init(coder:) .使用初始化程序初始化 VC 时,您应该使用该初始化程序,而不是init(coder:) If you use storyboards, then you should use instantiateViewController , or use segues to get new VCs.如果你使用故事板,那么你应该使用instantiateViewController ,或者使用 segues 来获取新的 VC。

So to achieve this syntax:所以要实现这个语法:

let viewController = ViewContorller(viewModel: viewModel)

You can put your VCs in xib files, and do:您可以将您的 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)
}

If you must use storyboards, then you can't use an initialiser syntax for initialising VCs.如果你必须使用故事板,那么你不能使用初始化语法来初始化 VC。 You can instead make a factory method, such as:您可以改用工厂方法,例如:

let viewController = ViewContorller.from(viewModel: viewModel)

And implement it using UIStoryboard.instantiateViewController .并使用UIStoryboard.instantiateViewController实现它。

This is why the initializer instantiateViewController(identifier:creator:) exists.这就是初始化程序instantiateViewController(identifier:creator:)存在的原因。

https://developer.apple.com/documentation/uikit/uistoryboard/3213989-instantiateviewcontroller https://developer.apple.com/documentation/uikit/uistoryboard/3213989-instantiateviewcontroller

You receive the coder and use it to call a custom initializer that itself calls the coder initializer but also does other custom initialization.您收到coder并使用它来调用自定义初始化器,该初始化器本身调用coder初始化器,但也执行其他自定义初始化。

To illustrate, suppose we have a ViewController class with a message String property to be presented to the user in a UILabel when the view appears.为了说明这一点,假设我们有一个 ViewController class,它有一个message字符串属性,当视图出现时,它会在 UILabel 中呈现给用户。 So we've given ViewController an init(coder:message:) initializer:所以我们给了 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
    }
}

Left to its own devices, however, the runtime will never call our init(coder:message:) initializer;然而,任其自生自灭,运行时永远不会调用我们的init(coder:message:)初始化程序; it knows nothing of it!它对此一无所知! The only way the runtime knows to instantiate a view controller from a storyboard is by calling init(coder:) .运行时知道从 storyboard 实例化视图 controller 的唯一方法是调用init(coder:) But we can call init(coder:message:) when we instantiate the view controller from the storyboard.但是当我们从 storyboard 实例化视图 controller 时,我们可以调用init(coder:message:)

Suppose this is the storyboard's initial view controller, and we're calling it in the scene delegate at launch time:假设这是故事板的初始视图 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()
}

We call instantiateViewController(identifier:creator:) and the creator: function calls init(coder:message:) — which, in turn, calls init(coder:) .我们调用instantiateViewController(identifier:creator:)creator: function 调用init(coder:message:) —— 反过来调用init(coder:) Thus our use of the creator: function is legal, and the view appears correctly.因此我们对creator: function 的使用是合法的,并且视图正确显示。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如果没有Storyboard,如何初始化自定义ViewController? - How do I initialize a custom ViewController when there's no Storyboard? 如何使用StoryBoard从另一个ViewController设置UIImageView的图像? - How to set image of the UIImageView from another ViewController using StoryBoard? 使用故事板时如何从应用程序委托中获取可见的viewController? - How to get visible viewController from app delegate when using storyboard? 使用Storyboard从ViewController访问自定义UITableViewCell - Accessing custom UITableViewCell from ViewController using Storyboard 使用故事板从 UITableviewcell 移动到 ViewController 并返回 - Move from UITableviewcell to a ViewController and back using storyboard 从情节提要中获取viewController,而不使用InstantiateViewControllerWithIdentifier - get viewController from storyboard, not using instantiateViewControllerWithIdentifier 如何从 xib 到 storyboard 的视图控制器? - How to segue from a xib to a viewcontroller from a storyboard? 使用情节提要如何与ViewController对象进行交互 - Using Storyboard how to interact with viewcontroller objects 如何从Storyboard initialVC(ContainerView)访问ViewController - How to access ViewController from Storyboard initialVC(ContainerView) 如何从故事板中的appdelegate推送viewcontroller - How to push viewcontroller from appdelegate in storyboard
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM