首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >NSOperation Queue waitUntilAllOperationsAreFinished导致NSOperation实例延迟执行

NSOperation Queue waitUntilAllOperationsAreFinished导致NSOperation实例延迟执行
EN

Stack Overflow用户
提问于 2021-09-15 03:55:29
回答 2查看 258关注 0票数 1

我们的应用程序目前使用NSOperation (Operation in Swift)来管理网络请求和数据解析的序列。某些代码需要在队列中的所有5项操作完成后执行,这通常是用GCD组实现的。

代码语言:javascript
复制
DispatchQueue.global().async {
    (0...5).forEach(){
        self.queue.addOperation(CustomOperation(value: $0))
    }
    self.queue.waitUntilAllOperationsAreFinished()
    print("All Tasks Done")
}

问题是,在所有5个操作完成之前,NSOperation实例不是deinit,这导致内存释放的时间比预期的晚。如果删除queue.waitUntilAllOperationsAreFinished,则实例将立即为deinit

我们已经添加了自动释放池来避免它。但是,当使用NSOperation时,是否可以立即使waitUntilAllOperationsAreFinished实例成为waitUntilAllOperationsAreFinished

waitUntilAllOperationsAreFinished打印

代码语言:javascript
复制
Begin Task 5
Begin Task 4
Begin Task 3
Begin Task 2
Begin Task 1
Begin Task 0
Finish Task 0
Finish Task 1
Finish Task 2
Finish Task 3
Finish Task 4
Finish Task 5
deinit 0
deinit 1
deinit 2
deinit 3
deinit 4
deinit 5
All Tasks Done

waitUntilAllOperationsAreFinished打印

代码语言:javascript
复制
All Tasks Done
Begin Task 0
Begin Task 1
Begin Task 4
Begin Task 3
Begin Task 5
Finish Task 0
Begin Task 2
deinit 0
Finish Task 1
deinit 1
Finish Task 2
deinit 2
Finish Task 3
deinit 3
Finish Task 4
deinit 4
Finish Task 5
deinit 5

定制操作。

代码语言:javascript
复制
class CustomOperation: Operation {
    
    public enum State {
        case ready
        case running
        case finished
    }

    private var state: State = .ready
    
    override var isAsynchronous: Bool { return true }
    
    override open var isExecuting: Bool { state == .running }

    override open var isFinished: Bool { state == .finished }

    var value: Int = 0
    
    init(value: Int) {
        super.init()
        
        self.value = value
    }
    
    override func main() {
        print("Begin Task \(value)")
        DispatchQueue.global().asyncAfter(deadline: .now()+DispatchTimeInterval.seconds(value)) {
            print("Finish Task \(self.value)")
            self.finish()
        }
    }
    
    func finish() {
        willChangeValue(forKey: "isExecuting")
        willChangeValue(forKey: "isFinished")
        state = .finished
        didChangeValue(forKey: "isFinished")
        didChangeValue(forKey: "isExecuting")
    }
    
    deinit {
        print("deinit")
    }
}
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2021-09-15 05:37:29

我不知道你的行为,但我不认为你能在这里做点什么。

如果您关心操作顺序,可以将队列设置为有一个maxConcurrentOperationCount为1,这样就可以保持顺序。

如果您关心内存,并且您有一些巨大的数据,您可以在finish()方法中去掉这些数据,或者使用completionBlock来传递它。

还有在OperationQueue属性上使用KVO的选项,它的大多数属性都与KVO和KVC兼容,您可以在其中一些属性上设置观察以触发回调。

如果您正在部署目标>=13,您可以使用组合体,就像已经由vadian编写的那样。

票数 1
EN

Stack Overflow用户

发布于 2021-09-15 04:58:26

一个比等待更好的方法是,例如观察操作计数。

代码语言:javascript
复制
import Combine

DispatchQueue.global().async {
     (0...5).forEach {
         queue.addOperation(CustomOperation(value: $0))
     }
 }

var store : AnyCancellable?

store = queue.publisher(for: \.operationCount)
    .sink { value in
        if value == 0 { print("All Tasks Done")}
    }

我的建议是联合使用,它也可以与传统的KVO

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/69186928

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档