【问题标题】:Segue to UIViewController without initializing a new object在不初始化新对象的情况下转到 UIViewController
【发布时间】:2015-10-20 05:07:28
【问题描述】:

我正在使用 Swift 2.0 在 iOS 9 中构建。我的起始 UIViewController 是我的菜单屏幕。它包含以下代码:

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    if let id = segue.identifier where id == "GamePlayScene" {
        self.gameVC = segue.destinationViewController as? GameViewController
        self.gameVC!.delegate = self
        if let s = sender as? GKTurnBasedMatch {
            self.gameVC!.match = s
        }
    }
}

当 segue 到我的 GameViewController 时,以下初始化会在 prepareForSegue 甚至被调用之前运行:

required init?(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
    GKLocalPlayer.localPlayer().registerListener(self) // I only want this once
}

在故事板中,我的 GameViewController 有一个“菜单”按钮,该按钮连接到视图控制器的退出小部件,并按预期展开到菜单。但是每当我再次执行 segue 时,都会再次调用 init,所以我现在有多个 GameViewControllers。我认为这会减慢我的应用程序速度,因为我使用的是 SKScenes。 如何在不每次都创建新对象的情况下执行转场?

func player(player: GKPlayer, receivedTurnEventForMatch match: GKTurnBasedMatch, didBecomeActive: Bool) {
    if didBecomeActive {
        // This event is what activated the app, so the user wants it right meow
        GameKitHelper.sharedInstance.match = match
        performSegueWithIdentifier("GamePlayScene", sender: match)
    }
}

【问题讨论】:

    标签: ios swift uiviewcontroller storyboard


    【解决方案1】:

    您可以将GameViewController 存储在一个单例中,这样它只需要创建一次。由于视图控制器只初始化一次,它节省了处理时间。对于使用两个视图控制器(例如您的游戏)的应用程序来说,这可能是一个很好的性能优化,需要经常在两者之间来回切换。

    这样做的方法是创建一个新的 Swift 类,并将其作为共享实例访问,其中第二个视图控制器存储在私有属性中。如果第二个视图控制器还没有被初始化,它就会被实例化。视图控制器的进一步检索返回存储的视图控制器,从而消除了初始化视图控制器的需要。创建、存储和返回视图控制器的操作由可公开访问的计算属性的 getter 处理。

    这是该类的代码:

    Singleton.swift:

    import Foundation
    import UIKit
    
    class Singleton {
    
        static let sharedInstance = Singleton()
    
        var gameViewController: GameViewController {
            get {
                if self.storedViewController == nil {
                    let storyboard = UIStoryboard(name: "Main", bundle: nil)
                    self.storedViewController = 
                         storyboard.instantiateViewControllerWithIdentifier("GameViewController") as? GameViewController
                }
    
                return self.storedViewController!
            }
        }
    
        private var storedViewController: GameViewController?
    
    }
    

    要使用它,必须使用 showViewController 方法来显示游戏视图控制器,而不是使用 segue。

    在我拥有的第一个视图控制器中:

    @IBAction func buttonWasPressed(sender: AnyObject) {
        let vc = Singleton.sharedInstance.gameViewController
        navigationController?.showViewController(vc, sender: self)
    }
    

    第二个控制器 (GameViewController)现在只会在第一个视图控制器上每次按下按钮时创建一次并重复使用

    【讨论】:

    • GameViewController 的退出功能是否仍然有效?当我放松到菜单时,是否有任何东西被释放?
    • @dem7w2 我的示例使用导航控制器。当按下后退按钮时,视图控制器不会被释放。使用此优化可能需要您更改在视图之间导航的方式。我不相信它会支持在情节提要中使用 segues。但是,使用 showViewController:sender:popViewControllerAnimated: 设置导航控制器相对容易。
    • 这比这要复杂一些,因为还有其他屏幕,例如选项和挑战以及单人模式,在进入游戏视图控制器之前需要查看额外的视图。不过,showViewController 很可能会满足我的需求,谢谢。
    • 没问题,@dem7w2。我很高兴这对你有用。祝你的游戏好运。
    【解决方案2】:
    GKLocalPlayer.localPlayer().registerListener(self) // I only want this once
    

    使一行代码在应用的生命周期内只运行一次的方法是使用dispatch_once

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-05-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-07-18
      • 2015-08-10
      • 1970-01-01
      • 2012-09-01
      相关资源
      最近更新 更多