Singleton SharedInstance函数被调用两次

时间:2016-09-04 19:42:41

标签: ios swift swift2 singleton nstimer

所有单例函数都是两次调用。 “Prova”功能和计时器的选择器是两次调用。

class Timer {
    static let sharedInstanceTimer = Timer()
    var TimerCounter : NSTimer = NSTimer()
    var Counter : Int = Int()
    var TimerGameOver : Int = Int()
    var TimerBonusMultipleCircle : Int = Int()
    var TimerBonusBigCircle : Int = Int()
    var TimerCounterInterval : NSTimeInterval = 1

    init()
    {
        self.Counter = 60
        self.TimerGameOver = 10
        self.TimerBonusMultipleCircle = 5
        self.TimerBonusBigCircle = 5
        self.TimerCounterInterval = 1
    }
    func StartTimerCounter()
    {
        self.TimerCounter = NSTimer.scheduledTimerWithTimeInterval(self.TimerCounterInterval, target: Game.sharedInstanceGame, selector: #selector(Game.sharedInstanceGame.UpdateAllCounter), userInfo: nil, repeats: true)
    }
    func StopTimerCounter()
    {
        self.TimerCounter.invalidate()
    }
}

并且...在另一个文件中,我呼叫StartTimerCounter()

import UIKit
class FirstViewController: UIViewController {
    static let sharedInstanceFirstViewController = FirstViewController()
    override func viewDidLoad() {
        super.viewDidLoad()
        let backButton = UIBarButtonItem(title: "00:00:60", style: UIBarButtonItemStyle.Plain, target: self, action: nil)
        backButton.tintColor = UIColor.whiteColor()
        navigationItem.leftBarButtonItem = backButton
        Circle.sharedInstanceCircle.CreateCircle()
        view.layer.addSublayer(Circle.sharedInstanceCircle.PrincipalCircle)
        Game.sharedInstanceGame.Play()


        // Do any additional setup after loading the view.
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    override func prefersStatusBarHidden() -> Bool {
        return true
    }

    func ReturnToMenu()
    {
       navigationController?.popViewControllerAnimated(true)
    }


    /*
    // MARK: - Navigation

    // In a storyboard-based application, you will often want to do a little preparation before navigation
    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
        // Get the new view controller using segue.destinationViewController.
        // Pass the selected object to the new view controller.
    }
    */

}

撇开我在下面建议修正的各种错误,我尝试了几种解决方案,但我找不到解决这个问题的方法。

1 个答案:

答案 0 :(得分:2)

有几点想法:

  1. 您的sharedInstanceTimer正在实例化Timer(本身就是NSTimer)。它不应该是NSTimer的子类。

  2. 然后将TimerCounter初始化为您从未使用的第二个计时器。

  3. 以上将实例化两个计时器。然后,每次调用它时,StartTimerCounter都会实例化另一个NSTimer。假设您只想要一个计时器,那么在开始一个计时器之前,您应该StartTimerCounter使任何先前计时器无效。

  4. 我会打电话给这个班级TimerManager,或类似的东西,以避免与Swift 3类型Timer冲突。

  5. 方法名称应以小写字母开头,属性也应如此。根据Swift 3 API准则的精神,您可能也希望缩短方法名称。

  6. 另外,如果你要定义一个单例,我会声明一个private init()初始值设定项,以防止其他类意外地实例化另一个TimerManager对象。

  7. 所以,产生的结果如下:

    class TimerManager {
        static let shared = TimerManager()
    
        private var timer: NSTimer?   // this certainly should be private
    
        // whether you make these private or not, or constants vs properties, is up to you
    
        private var tounter : Int = 60
        private var timerGameOver : Int = 10
        private var timerBonusMultipleCircle : Int = 5
        private var timerBonusBigCircle : Int = 5
        private var timerCounterInterval : NSTimeInterval = 1
    
        // make sure no one else accidentally instantiates another TimerManager
    
        private init() {
        }
    
        /// Start timer.
    
        func startTimer() {
            stopTimer()    // cancel prior timer, if any
    
            timer = NSTimer.scheduledTimerWithTimeInterval(timerCounterInterval, target: Game.sharedInstanceGame, selector: #selector(Game.sharedInstanceGame.updateAllCounter), userInfo: nil, repeats: true)
    
            Game.sharedInstanceGame.prova()
        }
    
        /// Stop timer.
    
        func stopTimer() {
            timer?.invalidate()
            timer = nil
        }
    }
    

    这里有一个不相关的,更深入的观察:我建议你保持计时器对象与Game对象松散耦合。所以,我会从这个课程中删除所有与“游戏”相关的内容:

    class TimerManager {
        static let shared = TimerManager()
    
        private var timer: NSTimer?   // this certainly should be private
        private var timerHandler: (() -> ())?
    
        // whether you make these private or not, or constants vs properties, is up to you
    
        private var timerCounterInterval: NSTimeInterval = 1
    
        // make sure no one else accidentally instantiates another TimerManager
    
        private init() {
        }
    
        /// Start timer.
        ///
        /// - parameter timerHandler: The closure that will be called once per second.
    
        func startTimer(timerHandler: () -> ()) {
            stopTimer()    // cancel prior timer, if any
    
            self.timerHandler = timerHandler
            timer = NSTimer.scheduledTimerWithTimeInterval(timerCounterInterval, target: self, selector: #selector(handleTimer(_:)), userInfo: nil, repeats: true)
        }
    
        @objc func handleTimer(timer: NSTimer) {
            timerHandler?()
        }
    
        /// Stop timer.
    
        func stopTimer() {
            timer?.invalidate()
            timerHandler = nil
            timer = nil
        }
    }
    

    然后,当Game对象想要启动计时器时,它可能会执行:

    TimerManager.shared.startTimer {
        self.updateAllCounter()
    }
    prova()
    

    现在,为了解决这个问题,你可能简化了你的计时器对象,也许这个TimerManager对象需要更多的东西(正如你的代码片段中没有引用的所有其他属性所建议的那样) ,但希望这说明了基本思想:TimerManager不应该涉及调用任何特定Game方法等的业务。它应该只是提供一种机制,通过该机制,调用者可以简单地提供定时器应该定期调用的代码块。