Swift:当调用者 viewController 为 deinit() 时,DispatchQueue.async 调用会发生什么

发布于 2025-01-10 01:28:46 字数 752 浏览 4 评论 0原文

我正在开发一个 ViewController,我在其中调用了 viewModel 来执行 DispatchQueue.async 调用。在异步任务开始之后和结束之前,我的任务 ViewController 通过按后退按钮来定义。在这种情况下,我的异步任务会发生什么?它会保留线程或内存块或导致内存泄漏吗?如果发生这种情况,有什么办法可以取消我的异步任务吗?

为了理解,我添加了演示类:

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

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

赠意 2025-01-17 01:28:46

由于没有人回答我天真的问题,我做了一些实验,这是我在 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

,实验结果是

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

从我的实验中,我了解到

  1. 异步调用可以保留在线程中,直到线程相关的任务完成
    尽管调用者类已定义,但已完成。
  2. 另外,另一点注意到与异步调用相关的变量和完成块保存着内存。

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.
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文