是否有一种好的方法来处理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
并将其存储在数组中。
我想在阵列完成时从阵列中删除该实例,以避免浪费内存。
我知道我可以做类似的事情,而不是数组
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?
}
答案 0 :(得分:2)
这是一个好主意,但实际上没有什么要删除的。当完成(完成或取消)在管道上进行时,管道上的所有内容都将以良好的顺序取消订阅,所有类(Subscription对象)都将被释放,依此类推。因此,在Future发出价值或失败后,唯一仍然有意义的“运行”是管道末端的接收器,它很小。
要查看此内容,请运行以下代码
for _ in 1...100 {
self.taskCaller()
}
并使用工具来跟踪您的分配。果然,此后有100个AnyCancellable对象,总计3KB。没有期货; startSomeTask
中分配的其他所有对象都不存在,而且它们很小(48字节),以至于它们没有关系。
答案 1 :(得分:2)
我在开发一个应用程序时问了自己同样的问题,该应用程序会生成大量最终存储在同一数组中的可取消项。对于长期存在的应用,数组大小可能会变得很大。
即使内存占用很小,它们仍然是对象,它们消耗堆,这会导致堆碎片及时。
我找到的解决方案是在发布者完成后删除可取消:
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)
}