我可以将私有变量传递给将通过 Storyboard 实例化的 UIViewController 吗?
Can I pass in private variables to a UIViewController that will be instantiate via a Storyboard?
我有一个 'root' UIViewController,它本身实例化了另外两个 UIViewController。但是我需要将一些东西传递给它们中的每一个,这必须在初始化时完成。
但是
所有 3 个 UIViewController 都通过 Storyboard 实例化。
这可能吗?或者我应该看看其他一些设计模式来传递这些数据吗?
具体来说,我试图避免紧密耦合,但是 'root' 一个正在实例化的 2 个 UIViewController 彼此不了解,但两者都要求它们知道变量的值。
我 可以 使这个变量在 'root' 上成为静态变量,但这会强制耦合。
我可以制作一个全局 'constants' swift 文件并将变量放在那里,但这看起来很脏而且很老套。
理想情况下,我想在实例化时将此变量传递给这些 UIViewController 中的每一个,但由于它们都是从 Storyboard 加载的,所以我无法让它工作。
我看过关于类似事情的博客和堆栈帖子,例如
https://blog.scottlogic.com/2014/11/20/swift-initialisation.html
但我还没有看到一个决定性的方法。
我是不是做错了?
下面的 'example' 代码 显然 不起作用,但它可以向您展示我正在尝试做的事情,当然条件是所有三个这些 UIViewController 中的一些在 Interface Builder 中有一个条目,并使用 Storyboard 中的条目进行实例化...
class root : UIViewController
{
private let a: CGFloat = 1.0
private let b: CGFloat = 10.0
private let vc1: firstViewController
private let vc2: secondViewController
override init()
{
self.vc1 = firstViewController(a: a, b: b)
self.vc2 = secondViewController(a: a, b: b)
super.init
}
}
class firstViewController : UIViewController
{
private let a: CGFloat
private let b: CGFloat
init(a: CGFloat, b: CGFloat)
{
self.a = a
self.b = b
super.init(aDecoder: Decoder)
}
}
这也归结为如何 'chain' UIViewController 实例化...我还没有找到相关的博客、教程或解释。
感谢您的帮助/建议。
典型的解决方案是实现 prepare(for:sender:)
,这使您有机会在目标视图控制器中设置属性。如果你想让它们保持松耦合,你可以使用一个协议:
protocol DataDestination {
var a: CGFloat? { get set }
var b: CGFloat? { get set }
}
class RootViewController: UIViewController {
private let a: CGFloat = 1.0
private let b: CGFloat = 10.0
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let destination = segue.destination as? DataDestination {
destination.a = a
destination.b = b
}
}
}
class FirstViewController: UIViewController, DataDestination {
var a: CGFloat?
var b: CGFloat?
override func viewDidLoad() {
super.viewDidLoad()
print(a,b) // by the time we hit this, those will be set
}
}
很明显,你会给你的协议起一个更有意义的名字,但我们可能想了解更多关于应用程序的信息,以便提出更好的建议。
除了 ,您还可以通过导航至 Interface Builder -> Identity Inspector 将 Storyboard ID 分配给第一个和第二个视图控制器。然后像这样实例化和设置它们:
let sb = UIStoryboard(name: "Main", bundle: nil)
if let firstVC = sb.instantiateViewController(withIdentifier: "firstVCIdentifier") as? FirstViewController {
firstVC.a = self.a // ('a' must not be private in firstVC)
}
并展示它们:
self.present(firstVC, animated: true, completion: nil)
我有一个 'root' UIViewController,它本身实例化了另外两个 UIViewController。但是我需要将一些东西传递给它们中的每一个,这必须在初始化时完成。
但是
所有 3 个 UIViewController 都通过 Storyboard 实例化。
这可能吗?或者我应该看看其他一些设计模式来传递这些数据吗?
具体来说,我试图避免紧密耦合,但是 'root' 一个正在实例化的 2 个 UIViewController 彼此不了解,但两者都要求它们知道变量的值。
我 可以 使这个变量在 'root' 上成为静态变量,但这会强制耦合。
我可以制作一个全局 'constants' swift 文件并将变量放在那里,但这看起来很脏而且很老套。
理想情况下,我想在实例化时将此变量传递给这些 UIViewController 中的每一个,但由于它们都是从 Storyboard 加载的,所以我无法让它工作。
我看过关于类似事情的博客和堆栈帖子,例如
https://blog.scottlogic.com/2014/11/20/swift-initialisation.html
但我还没有看到一个决定性的方法。
我是不是做错了?
下面的 'example' 代码 显然 不起作用,但它可以向您展示我正在尝试做的事情,当然条件是所有三个这些 UIViewController 中的一些在 Interface Builder 中有一个条目,并使用 Storyboard 中的条目进行实例化...
class root : UIViewController
{
private let a: CGFloat = 1.0
private let b: CGFloat = 10.0
private let vc1: firstViewController
private let vc2: secondViewController
override init()
{
self.vc1 = firstViewController(a: a, b: b)
self.vc2 = secondViewController(a: a, b: b)
super.init
}
}
class firstViewController : UIViewController
{
private let a: CGFloat
private let b: CGFloat
init(a: CGFloat, b: CGFloat)
{
self.a = a
self.b = b
super.init(aDecoder: Decoder)
}
}
这也归结为如何 'chain' UIViewController 实例化...我还没有找到相关的博客、教程或解释。
感谢您的帮助/建议。
典型的解决方案是实现 prepare(for:sender:)
,这使您有机会在目标视图控制器中设置属性。如果你想让它们保持松耦合,你可以使用一个协议:
protocol DataDestination {
var a: CGFloat? { get set }
var b: CGFloat? { get set }
}
class RootViewController: UIViewController {
private let a: CGFloat = 1.0
private let b: CGFloat = 10.0
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let destination = segue.destination as? DataDestination {
destination.a = a
destination.b = b
}
}
}
class FirstViewController: UIViewController, DataDestination {
var a: CGFloat?
var b: CGFloat?
override func viewDidLoad() {
super.viewDidLoad()
print(a,b) // by the time we hit this, those will be set
}
}
很明显,你会给你的协议起一个更有意义的名字,但我们可能想了解更多关于应用程序的信息,以便提出更好的建议。
除了
let sb = UIStoryboard(name: "Main", bundle: nil)
if let firstVC = sb.instantiateViewController(withIdentifier: "firstVCIdentifier") as? FirstViewController {
firstVC.a = self.a // ('a' must not be private in firstVC)
}
并展示它们:
self.present(firstVC, animated: true, completion: nil)