首页 > 解决方案 > 发布者完成时从 AnyCancellable 数组中删除

问题描述

有没有一种好方法来处理数组以在完成/取消时AnyCancellable删除存储的?AnyCancellable

说我有这个

import Combine
import Foundation

class Foo {

    private var cancellables = [AnyCancellable]()

    func startSomeTask() -> Future<Void, Never> {
        Future<Void, Never> { promise in
            DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(2)) {
                promise(.success(()))
            }
        }
    }

    func taskCaller() {
        startSomeTask()
            .sink { print("Do your stuff") }
            .store(in: &cancellables)
    }

}

每次taskCaller调用时,AnyCancellable都会创建 a 并将其存储在数组中。我想在完成后从数组中删除该实例,以避免内存浪费。

我知道我可以做这样的事情,而不是数组

var taskCancellable: AnyCancellable?

并通过执行以下操作存储可取消的:

taskCancellable = startSomeTask().sink { print("Do your stuff") }

但这会最终创建几个可取消的单并且会污染代码。我不想要这样的课

class Bar {

    private var task1: AnyCancellable?
    private var task2: AnyCancellable?
    private var task3: AnyCancellable?
    private var task4: AnyCancellable?
    private var task5: AnyCancellable?
    private var task6: AnyCancellable?

}

标签: swiftcombine

解决方案


我在开发一个生成大量可取消项的应用程序时问自己同样的问题,这些可取消项最终存储在同一个数组中。对于长期存在的应用程序,数组大小可能会变得很大。

即使内存占用很小,那些仍然是对象,它们会消耗堆,这会导致堆碎片。

我找到的解决方案是在发布者完成时删除可取消的:

func consumePublisher() {
    var cancellable: AnyCancellable!
    cancellable = makePublisher()
        .sink(receiveCompletion: { [weak self] _ in self?.cancellables.remove(cancellable) },
              receiveValue: { doSomeWork() })
    cancellable.store(in: &cancellables)
}

确实,代码不是那么漂亮,但至少没有内存浪费 :)

一些高阶函数可用于使此模式在同一类的其他地方可重用:

func cleanupCompletion<T>(_ cancellable: AnyCancellable) -> (Subscribers.Completion<T>) -> Void {
    return { [weak self] _ in self?.cancellables.remove(cancellable) }
}

func consumePublisher() {
    var cancellable: AnyCancellable!
    cancellable = makePublisher()
        .sink(receiveCompletion: cleanupCompletion(cancellable),
              receiveValue: { doSomeWork() })
    cancellable.store(in: &cancellables)
}

或者,如果您需要支持来完成工作:

func cleanupCompletion<T>(_ cancellable: AnyCancellable) -> (Subscribers.Completion<T>) -> Void {
        return { [weak self] _ in self?.cancellables.remove(cancellable) }
    }
    
func cleanupCompletion<T>(_ cancellable: AnyCancellable, completionWorker: @escaping (Subscribers.Completion<T>) -> Void) -> (Subscribers.Completion<T>) -> Void {
    return { [weak self] in
        self?.cancellables.remove(cancellable)
       completionWorker($0)
    }
}

func consumePublisher() {
    var cancellable: AnyCancellable!
    cancellable = makePublisher()
        .sink(receiveCompletion: cleanupCompletion(cancellable) { doCompletionWork() },
              receiveValue: { doSomeWork() })
    cancellable.store(in: &cancellables)
}

推荐阅读