如何使用它的编码器从故事板初始化 ViewController

发布于 2025-01-09 12:58:00 字数 1306 浏览 2 评论 0原文

我意识到这可能很难实现,但我希望能够使用 init(coder: NSCoder)storyboard 初始化 ViewControllers直接运行。我的意思是不使用 storyboard.instantiateViewController(identifier: coder: ) - 我知道我可以使用它,但这是我想跳过的。相反,我更愿意在 ViewController 中有一个 init,如下所示: init(viewModel: ViewModel) 并使用此 init 从 storyboard 初始化此 ViewController。在这个初始化中,我想象有某种机制可以打开我的故事板,并以某种方式提取它的编码器,以便我可以编写:

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.instantiateViewController(identifier: String(describing: Self.self)) { coder in
    Self.init(coder: coder, viewModel: viewModel)
}

,但我正在寻找一种不使用 instantiateViewController 的方法,而只是能够获取 coder,以便稍后我可以像这样启动 VC:

let viewController = ViewContorller(viewModel: viewModel)

所以问题是如何解压storyboard,并检索某些ViewControllercoder对象代码>.

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. I mean not using storyboard.instantiateViewController(identifier: coder: ) - I know I could use this, but this is what I would like to skip. 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. Inside this init I imagine having some mechanism that would open my storyboard, and extracted it's coder somehow, so that I could write:

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.
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:

let viewController = ViewContorller(viewModel: viewModel)

So the question is how to unpack storyboard, and retrieve coder object for some ViewController.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

山川志 2025-01-16 12:58:00

你不应该这样做。

作为 init(nibName:bundle:) 的文档 说:

这是此类的指定初始值设定项。当使用故事板定义视图控制器及其关联视图时,您永远不会直接初始化视图控制器类。相反,视图控制器会在触发 segue 时由 Storyboard 自动实例化,或者在您的应用调用 Storyboard 对象的 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 实现它。

You are not supposed to do this.

As the documentation of init(nibName:bundle:) says:

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. 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.

When initialising a VC using an initialiser, that initialiser is what you should use, not init(coder:). If you use storyboards, then you should use instantiateViewController, or use segues to get new VCs.

So to achieve this syntax:

let viewController = ViewContorller(viewModel: viewModel)

You can put your VCs in xib files, and do:

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. You can instead make a factory method, such as:

let viewController = ViewContorller.from(viewModel: viewModel)

And implement it using UIStoryboard.instantiateViewController.

晨曦慕雪 2025-01-16 12:58:00

这就是初始化器 instantiateViewController(identifier:creator:) 存在的原因。

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

您收到 coder 并使用它来调用自定义初始值设定项,该初始值设定项本身会调用coder 初始化程序还执行其他自定义初始化。

为了说明这一点,假设我们有一个 ViewController 类,其中包含一个 message String 属性,当视图出现时,该类将在 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:) 初始化器;它对此一无所知!运行时知道从故事板实例化视图控制器的唯一方法是调用 init(coder:)。但是当我们从故事板实例化视图控制器时,我们可以调用 init(coder:message:) 。

假设这是故事板的初始视图控制器,我们在启动时在场景委托中调用它:

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:函数调用 init(coder:message:) — 而后者又调用 init(coder:)。因此,我们对creator:函数的使用是合法的,并且视图显示正确。

This is why the initializer instantiateViewController(identifier:creator:) exists.

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.

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. So we've given ViewController an init(coder:message:) initializer:

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; it knows nothing of it! The only way the runtime knows to instantiate a view controller from a storyboard is by calling init(coder:). But we can call init(coder:message:) when we instantiate the view controller from the storyboard.

Suppose this is the storyboard's initial view controller, and we're calling it in the scene delegate at launch time:

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:). Thus our use of the creator: function is legal, and the view appears correctly.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文