发布者完成后从 AnyCancellable 数组中移除
Remove from array of AnyCancellable when publisher finishes
有没有一种好的方法来处理 AnyCancellable
的数组,以便在 finished/cancelled 时删除存储的 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 喜欢
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?
}
这是个好主意,但确实没有什么可删除的。当完成(完成或取消)到达管道时,管道上的所有内容都按良好顺序取消订阅,所有 类(订阅对象)都被释放,等等。因此,在您的 Future 发出值或失败后,唯一仍然有意义 "alive" 的是管道末端的 Sink,它很小。
看到这个,运行这个代码
for _ in 1...100 {
self.taskCaller()
}
并使用 Instruments 来跟踪您的分配。果然,之后有 100 个 AnyCancellable 对象,总共 3KB。没有期货; startSomeTask
中分配的其他对象中的 none 仍然存在,而且它们非常小(48 字节),即使它们存在也没关系。
我问自己同样的问题,当时我正在开发一个生成大量可取消项的应用程序,这些可取消项最终存储在同一个数组中。对于长期存在的应用程序,数组大小可能会变得很大。
即使内存占用很小,那些仍然是对象,消耗堆,及时导致堆碎片。
我找到的解决方案是在发布者完成时删除可取消的:
func consumePublisher() {
var cancellable: AnyCancellable!
cancellable = makePublisher()
.sink(receiveCompletion: { [weak self] _ in self?.cancellables.remove(cancellable) },
receiveValue: { doSomeWork() })
cancellable.store(in: &cancellables)
}
确实,代码不是那么漂亮,但至少没有内存浪费:)
可以使用一些高阶函数使这个模式在相同的其他地方可以重用class:
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([=12=])
}
}
func consumePublisher() {
var cancellable: AnyCancellable!
cancellable = makePublisher()
.sink(receiveCompletion: cleanupCompletion(cancellable) { doCompletionWork() },
receiveValue: { doSomeWork() })
cancellable.store(in: &cancellables)
}
有没有一种好的方法来处理 AnyCancellable
的数组,以便在 finished/cancelled 时删除存储的 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 喜欢
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?
}
这是个好主意,但确实没有什么可删除的。当完成(完成或取消)到达管道时,管道上的所有内容都按良好顺序取消订阅,所有 类(订阅对象)都被释放,等等。因此,在您的 Future 发出值或失败后,唯一仍然有意义 "alive" 的是管道末端的 Sink,它很小。
看到这个,运行这个代码
for _ in 1...100 {
self.taskCaller()
}
并使用 Instruments 来跟踪您的分配。果然,之后有 100 个 AnyCancellable 对象,总共 3KB。没有期货; startSomeTask
中分配的其他对象中的 none 仍然存在,而且它们非常小(48 字节),即使它们存在也没关系。
我问自己同样的问题,当时我正在开发一个生成大量可取消项的应用程序,这些可取消项最终存储在同一个数组中。对于长期存在的应用程序,数组大小可能会变得很大。
即使内存占用很小,那些仍然是对象,消耗堆,及时导致堆碎片。
我找到的解决方案是在发布者完成时删除可取消的:
func consumePublisher() {
var cancellable: AnyCancellable!
cancellable = makePublisher()
.sink(receiveCompletion: { [weak self] _ in self?.cancellables.remove(cancellable) },
receiveValue: { doSomeWork() })
cancellable.store(in: &cancellables)
}
确实,代码不是那么漂亮,但至少没有内存浪费:)
可以使用一些高阶函数使这个模式在相同的其他地方可以重用class:
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([=12=])
}
}
func consumePublisher() {
var cancellable: AnyCancellable!
cancellable = makePublisher()
.sink(receiveCompletion: cleanupCompletion(cancellable) { doCompletionWork() },
receiveValue: { doSomeWork() })
cancellable.store(in: &cancellables)
}