0

All singleton functions are twice calls. The "Prova" function, and the selector of the timer are twice calls.

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()
    }
}

And... In another file I call 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.
    }
    */

}

Leaving aside the various errors that I corrected as suggested below I have tried several solutions but I can not find the solution to this problem.

Rob
  • 415,655
  • 72
  • 787
  • 1,044

1 Answers1

3

A couple of thoughts:

  1. Your sharedInstanceTimer is instantiating Timer (which is, itself, a NSTimer). It should not subclass NSTimer.

  2. You then initialize TimerCounter to a second timer which you never use.

  3. The above will instantiate two timers. You then have StartTimerCounter that instantiates another NSTimer every time you call it. Assuming you want only one timer, you should should have StartTimerCounter invalidate any prior timer before starting a new one.

  4. I'd call this class TimerManager, or something like that, to avoid clashes with Swift 3 type, Timer.

  5. Method names should start with lowercase letters, as should properties. In the spirit of the Swift 3 API guidelines, you might want to shorten the method names, too.

  6. Also, if you're going to define a singleton, I'd declare a private init() initializer, to prevent other classes from accidentally ever instantiating another TimerManager object.

So, that yields something like:

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
    }
}

An unrelated, deeper observation here: I'd suggest that you keep the timer object loosely coupled with respect to the Game object. So, I'd excise all "game" related stuff from this class:

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
    }
}

Then, when the Game object wants to start a timer, it might do:

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

Now, perhaps you simplified your timer object for the purpose of this question and perhaps there's more that's needed in this TimerManager object (as suggested by all these other properties that aren't otherwise referenced in your code snippet), but hopefully this illustrates the basic idea: The TimerManager shouldn't be involved in the business of calling any specific Game methods or the like. It should simply provide a mechanism by which the caller can simply supply a block of code that the timer should periodically invoke.

Rob
  • 415,655
  • 72
  • 787
  • 1,044
  • I would also ask why this class is a singleton? Given that it now (correctly) has a delegation pattern, it makes my spidey sense tingle; delegates and singletons mean the potential for delegate-wars. This should probably be a simple class that can be instantiated as required with appropriate arguments to `init`. If the `Game` only ever creates one instance, so be it, but that doesn't mean they should use a singleton – Paulw11 Sep 04 '16 at 21:01
  • I agree. IMHO, the same is true with `Game`, itself. But I thought I may have already packed too much in this answer. – Rob Sep 04 '16 at 21:06
  • 1
    Yes. And I just saw from their edit that they have a view controller singleton too! – Paulw11 Sep 04 '16 at 21:08
  • The truth is that I do not understand very well the use of the singleton and am looking to gain experience but continues to call him twice even with the solutions proposed here. – Luigi Festinante Sep 04 '16 at 21:08
  • Singletons are intoxicatingly simple to use, but introduce all sorts of subtle issues. It's admittedly a matter of debate (which is discouraged here on Stack Overflow), but I might refer you to [What is so bad about singletons?](http://stackoverflow.com/questions/137975) and [What's alternative to singleton?](http://stackoverflow.com/questions/1300655). Singletons can be useful in generic utilities, such as logging mechanisms or the like, but should generally be avoided for reasons that increasingly manifest themselves in larger projects. – Rob Sep 04 '16 at 21:17
  • If you say "I only need one right now" that is a bad reason to have a singleton. "There should be only one ever" is a much better reason. And singleton with a delegate that isn't a singleton is weird. – gnasher729 Sep 04 '16 at 22:16
  • And even if you will have "only one ever", it doesn't necessarily mean that it is a good candidate for a singleton. IMHO, none of these (neither the `FirstViewController`, the `Game`, nor this timer manager) should be singletons. – Rob Sep 05 '16 at 02:10