我有一个具有属性的视图控制器。
class GameVC: UIViewController {
var game:Game?
override func viewDidLoad() {
super.viewDidLoad()
}
}
对于视图控制器来说,它必须具有游戏属性。出于这个原因,我希望该属性不是可选的(当我在整个过程中使用它时,我也不想打开它。)
我目前正在压制VC之前准备segue并设置游戏属性。这是因为我绝对想要使用segues和storyboard。无论如何,我可以让这个视图控制器有一个自定义初始化,仍然使用segues和故事板?
答案 0 :(得分:1)
是。你有两个选择:
在声明中初始化:
class GameVC: UIViewController {
let game = Game()
实施init(coder:)
或awakeFromNib
:
class GameVC: UIViewController {
let game : Game
required init?(coder aDecoder: NSCoder) {
self.game = Game()
super.init(coder:aDecoder)
}
答案 1 :(得分:0)
不,Storyboard(和XIB文件)使用init?(coder:)
来实例化元素,不能将其他参数传递给此init。
通常的做法是使用隐式展开选项:
var game:Game!
这样,您可以像非可选属性一样使用它,如果在使用之前未设置,它将在运行时崩溃。
如果您在prepare(for:sender:)
中设置此属性,则会在viewDidLoad
中准备好,以便安全使用。
答案 2 :(得分:0)
在我的应用中,我只使用类似
的内容 var game = Game()
这样它永远不会是nil
,我可以在我发现之前设置值。
答案 3 :(得分:0)
在我看来,使用故事板时依赖注入没有好办法。我认为故事板违背了面向对象的设计原则。对于团队中的软件开发,除了原型设计外,我不建议使用它们。
相反,我使用简单的xib文件并尝试使屏幕(也称为UIViewControllers)尽可能独立。我还在自己的线框类中的屏幕之间实现导航,以将动画导航与UIViewController的主要目的(构建/管理视图树)分开。然后,可以在不完全失去使用界面构建器的好处的情况下注入必要的对象。
示例:
final class MyViewController: UIViewController {
convenience override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
self.init()
}
convenience required init(coder aDecoder: NSCoder) {
self.init()
}
convenience init() {
fatalError("Not supported!")
}
init(viewModel: ViewModel, wireframe: Wireframe) {
self.viewModel = viewModel
self.wireframe = wireframe
super.init(nibName: "MyViewController", bundle: Bundle(for: type(of: self)))
}
private let viewModel: ViewModel
private let wireframe: Wireframe
override func viewDidLoad() {
super.viewDidLoad()
// do something with viewModel
}
@IBAction func close() {
wireframe.close()
}
}
let wireframe: Wireframe = ConcreteWireframe()
let viewModel: ViewModel = ConcreteViewModel()
let screen: UIViewController = MyViewController(viewModel: viewModel, wireframe: wireframe)