在故事板中使用segue会使视图控制器具有非可选属性?

时间:2017-03-07 18:24:34

标签: ios swift uiviewcontroller segue

我有一个具有属性的视图控制器。

class GameVC: UIViewController {

    var game:Game?
    override func viewDidLoad() {
        super.viewDidLoad()
    }
}

对于视图控制器来说,它必须具有游戏属性。出于这个原因,我希望该属性不是可选的(当我在整个过程中使用它时,我也不想打开它。)

我目前正在压制VC之前准备segue并设置游戏属性。这是因为我绝对想要使用segues和storyboard。无论如何,我可以让这个视图控制器有一个自定义初始化,仍然使用segues和故事板?

4 个答案:

答案 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)