Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to quit "DispatchQueue.main.asyncAfter" in Swift

Tags:

xcode

ios

swift

I want to quit "DispatchQueue.main.asyncAfter" when deinit is called.

subView.swift

DispatchQueue.main.asyncAfter(deadline: .now() + 5.0) {
    self.doSomething()
}

func doSomething(){ 
    if self.subView.flgA == false { //error because subView's deinit is already called
        //...
    }
}

When ViewController do _ = self.navigationController?.popViewController(animated: true) and deinit is called, deinit in ViewController and subView is called at first and after a few minutes doSomething() is called. I want to stop doSomething() when popViewController is executed. How can I do it?

like image 739
K.K.D Avatar asked Apr 18 '18 07:04

K.K.D


2 Answers

You could schedule a Timer with this code block

let timer = Timer.scheduledTimer(withTimeInterval: 5.0, repeats: false) { [weak self] timer in
    self?.doSomething()
}

hold on to the timer and cancel it before popViewController like this:

timer.invalidate()

Notice the [weak self] and the self?.domeSomething() which I put there to avoid the hard reference to the viewcontroller and read Laffen's more detailed answer on this.

like image 136
nosyjoe Avatar answered Oct 18 '22 05:10

nosyjoe


In Swift we have something called ARC(Automatic Reference Counting). ARC will make sure any object with at least one strong reference to it, will not be removed from memory.

In your case you're creating a strong reference to self in the closure of the async task created by DispatchQueue.main.asyncAfter.

You need to tell the compiler that this reference is either weak or unowned(See attached link for more info.), this will enable the instance of self to be deinitialised even though you have a reference to self from the closure.

The weak keyword can be used in cases where you want the closure to run and make actions that doesn't require a reference to self. This is helpful to use if you don't know if self is alive or not.

The unowned keyword can be used in cases where you don't need the closure to run without a reference to self. This must be used in cases where you know self self is still alive.

Getting a weak or unowned reference of self in the closure can be achieved like in the example below:

DispatchQueue.main.asyncAfter(deadline: .now() + 5.0) {
    [weak self] in
    self?.doSomething()
}

DispatchQueue.main.asyncAfter(deadline: .now() + 5.0) {
    [unowned self] in
    self.doSomething()
}

It's worth mentioning that if you're not using a deadline, but calling .async { ... } directly does not result in capturing self and therefore can be used safely without defining weak/unowned self.

like image 31
Laffen Avatar answered Oct 18 '22 05:10

Laffen