0

I am working on a ViewController where I called my viewModel to do a DispatchQueue.async call. After the async task starts and before the end my task ViewController is deinited by pressing the back button. In that case, what will be happened to my async task? Is it gonna hold a thread or a memory block or cause a memory leak? If that happens, is there any way to cancel my async task?

For understanding, I am adding demo classes:

Class A: ViewController {
    let viewModel = B()

    func callViewModelAsyncFunction() {
       viewModel.viewModelAsyncFunction()
    }
}

Class B {
    private let sessionQueue = DispatchQueue(label: "Session.Queue")
    private let sessionGroup = DispatchGroup()
    
    func viewModelAsyncFunction() {
       sessionQueue.async {
           self.sessionGroup.wait()
           self.sessionGroup.enter()
        
           //do my other task signal producer call {
           //}
       }
    }
}
  • Swift uses Automatic Reference Counting. Your `deinit` wont be called if there are strong references to it. "After the async task starts my ViewController is deinited" - Thats not going to happen if your task references the ViewController – Raildex Feb 24 '22 at 09:42
  • @Raildex I also thought in your case. But I found that after my async call and before that function task finished (I mainly call this async call to open the web browser). My viewController deinit is called. Oh, I forgot to add that I press back button after call the async task. – Md Abul Kashem Feb 24 '22 at 09:55
  • Which VC is deinit ? A or B it both ? – Ptit Xav Feb 24 '22 at 15:53
  • @PtitXav Class A: VC have deinit and B class mainly for ViewModel – Md Abul Kashem Feb 24 '22 at 15:57

1 Answers1

1

Since no one goona respond to my naive question, I do some experiments, and here is my experiment code on Playgrounds

import Foundation


final class ClassA {
    let viewModel: ViewModel
    let classB: ClassB
    let time: Int
    init(viewModel: ViewModel, classB: ClassB, time: Int) {
        print("Init Class A")
        self.viewModel = viewModel
        self.classB = classB
        self.time = time
    }
    
    func doBackGroundTaskInViewModel() {
        viewModel.doBackGroundTask(anotherClass: classB, completion: {
            print("Block task is done")
        })
    }
    
    deinit {
        
        print("Class A deinited and initTime \(time)")
    }
}

final class ClassB {
    let time: Int
    init(time: Int) {
        print("Init Class B")
        self.time = time
    }
    
    deinit {
        print("Class B deinited and InitTime:\(time)")
    }
    
    func printClassBInformation() {
        sleep(2)
        print("Claas B still alive")
        printCurrentTime()
        
    }
}

final class ViewModel {
    private let sessionQueue = DispatchQueue(label: "Session.Queue")
    private let sessionGroup = DispatchGroup()
    func doBackGroundTask(anotherClass: ClassB, completion:  @escaping() -> Void) {
        sessionQueue.async {
            DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {
                printCurrentTime()
                anotherClass.printClassBInformation()
                completion()
            }
        }
    }
    
    init() {
        print("Init Class ViewModel")
    }
    deinit {
        print("ViewModel deinitd")
    }
}

func printCurrentTime () {
    let date = Date()
    let calendar = Calendar.current
    print(calendar.component(.second, from: date))
}



var classA: ClassA? = ClassA(viewModel: .init(), classB: .init(time: 1), time: 1)
printCurrentTime()

classA?.doBackGroundTaskInViewModel()

classA = ClassA(viewModel: .init(), classB: .init(time: 2), time: 2)
classA?.doBackGroundTaskInViewModel()
classA = nil

And experiment result is

Init Class ViewModel
Init Class B
Init Class A
51
Init Class ViewModel
Init Class B
Init Class A
Class A deinited and initTime 1
ViewModel deinitd
Class A deinited and initTime 2
ViewModel deinitd
53
Claas B still alive
55
Block task is done
Class B deinited and InitTime:1
55
Claas B still alive
57
Block task is done
Class B deinited and InitTime:2

From my experiment, I understand that

  1. Async call can remain in the thread until thread-related task is completed although the caller class is deinited.
  2. Also, another point notices that async call-related variables and completion block hold the Memory.