繁体   English   中英

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

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM