SWIFT: invalidate() - swift

I use NSTimer in swift
I start NSTimer on mainViewController and when I click on button I move to another view (type: Modal) and timer works in Background Everything's OK, but when I back main viewController my timer is duplicated so... How to stop timer on antoher View?
override func viewDidLoad() {
super.viewDidLoad()
countDownTimer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: "timerDown", userInfo: nil, repeats: true)
}

If viewDidLoad executes again when you "come back" from your modal view, you're probably not actually coming back but triggering a segue to a new instance. If you return to the main view using an unwind segue, viewDidLoad will not execute again and you will be on your original instance if you need to stop the timer.

As I understood your goal is that you don't duplicate the timer.
In order to do this you can simply check if the timer is null...
override func viewDidLoad() {
super.viewDidLoad()
if(countDownTimer==nil)
{
countDownTimer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: "timerDown", userInfo: nil, repeats: true)
}
}

Related

scheduledTimer not firing if I navigate to two viewcontrollers

I have a weak scheduledTimer:
weak var timer = Timer.scheduledTimer(timerInterval: 2.0, target: self, selector: #selector(fire), userInfo: ["id",id], repeats: false)
If I begin this timer and navigate to only one viewController, it will fire in the background with no issue. However, if I navigate to a second viewController before the timer fires, it will never go off. Any idea why this is happening?
To define
class viewController: UIViewController
{
var timer = Timer()
use in other function
func one()
{
timer = Timer.scheduledTimer(timeInterval: 2.0, target: self, selector: #selector(backClick), userInfo: ["id"], repeats: false)
}
func two()
{
timer = Timer.scheduledTimer(timeInterval: 2.0, target: self, selector: #selector(backClick), userInfo: ["id"], repeats: false)
}
inValidate() timer
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
timer.fire()
}
Because of that was weak like #Alexandr Kolesnik 's comment, or may be you invalidated when first one is disappeared.

Swift MacOX - Popover segue creates multiple view controller instances without destroying them when they are dismissed

I'm creating a popover style view controller in storyboard like this
Then I click the button, the view controller shows and when I click anywhere outside, the view controller is "dismissed".
However, when I click the button again, a new instance of the view controller is lunched and the previous one is still running. I have tried deinit but it's not getting called when the view controller is "dismissed".
How can I either destroy the view controller instance when clicking outside, or "show" the already created instance?
My code in the view controller:
class FileTransViewController: NSViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do view setup here.
timer = Timer.scheduledTimer(timeInterval: 0.25, target: self, selector: #selector(updateProgress), userInfo: nil, repeats: true)
//print(123)
print("\(self)")
}
deinit {
print("destroyed")
if let timer = timer {
timer.invalidate()
}
}
#objc func updateProgress() {
print("updating progress")
}
}
The problem has nothing to do with popovers. You are leaking because you retain the timer while the timer retains you — a classic retain cycle.
To break the cycle, you must invalidate the timer. You cannot do this in deinit, because by definition it cannot be called until after you break the cycle. NSPopover.willCloseNotification might be a good opportunity.
As #matt says, you have problem with retain cycle. You can avoid it using Timer with block where you can declare weak reference for self
timer = Timer.scheduledTimer(withTimeInterval: 0.25, repeats: true) { [weak self] timer in
guard let self = self else {
timer.invalidate()
return
}
print("updating progress")
}
You also don't need deinit in this case since you're invalidating timer inside guard's else block and you also don't need variable timer and you can just write Timer if you don't want to invalidate timer manually somewhere else
override func viewDidLoad() {
super.viewDidLoad()
Timer.scheduledTimer(...) { ... }
}

swift xcode - disable UIbutton from being pressed once Timer is running

I have a button called start that starts the TIMER counting , I want to disable it from being pressed again when the TIMER is counting other wise it makes the TIMER start counting twice as fast.
#IBAction func start(_ sender: Any) {
timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(CountUpVC.action), userInfo: nil, repeats: true)
Thanks in advance.
It's best done with an observer on the timer:
var timer : Timer? {
didSet {
start.isEnabled = !(timer?.isValid ?? false)
}
}
When you invalidate it, you should set it to nil to trigger didSet and enable the button again:
timer?.invalidate()
timer = nil

Button needs to be disapear and come back

I've got now an app that if you click on a button it will disappear, now I want to make the button disappear even when your not clicking on that button, but it will come back in a few seconds (or even less than a second). On the moment this is how the button looks in the code.
#IBAction func increaseCount(button: UIButton) -> Void {
button.hidden = true
ourScore.text = "\(++score)"
let time = dispatch_time(DISPATCH_TIME_NOW, Int64(Double((arc4random_uniform(1) + 2)) * Double(NSEC_PER_SEC)))
dispatch_after(time, dispatch_get_main_queue()) {
button.hidden = false
}
}
How is it possible to make the button disappear even when your not clicking it, but it will come back in just a few seconds (and less than a second) back? The time should be random between 2 and a half second. When your clicking it should also disappear and it will come back less than 2 seconds.
Who could help me?
This code will have the button appear and reappear on its own every 2 seconds. You can modify the time so it is random (if you need help with that, let me know).
Link your button on the story board and the code below should do the trick.
#IBOutlet weak var button: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
button.hidden = true
NSTimer.scheduledTimerWithTimeInterval(2, target: self, selector: "appear:", userInfo: self, repeats: false)
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func appear(timer: NSTimer) {
self.button.hidden = true
NSTimer.scheduledTimerWithTimeInterval(2, target: self, selector: "disappear:", userInfo: self, repeats: false)
}
func disappear(timer: NSTimer) {
self.button.hidden = false
NSTimer.scheduledTimerWithTimeInterval(2, target: self, selector: "appear:", userInfo: self, repeats: false)
}
EDIT: For the button to disappear when clicked, register an Action event from the button and use the code:
#IBAction func clicked(sender: UIButton) {
self.button.hidden = true
NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: "appear:", userInfo: self, repeats: false)
}
Again, this hides it just for 1 second when it is clicked, but you can change the time to be random.
Edit 2: You should see this:

NSTimer doesn't get fired repeatedly in my Swift code

I scheduled a timer in my viewDidAppear: method, but it just fire once and never fire again, the code is just like below
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
timer = NSTimer(timeInterval: 1, target: self, selector: "test", userInfo: nil, repeats: true)
timer.fire()
}
func test() {
print("timer test")
}
Actually, you didn't schedule it. Try this:
timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: Selector("test"), userInfo: nil, repeats: true)
And get rid of timer.fire().
Be aware that if you create a timer in viewDidAppear then a new timer will be created every time your view appears.