iOS Swift联合收割机:取消一套<;任何可取消的>;
如果我已将可取消集存储到ViewController中:iOS Swift联合收割机:取消一套<;任何可取消的>;,ios,swift,swiftui,ios13,combine,Ios,Swift,Swiftui,Ios13,Combine,如果我已将可取消集存储到ViewController中: private var bag = Set<AnyCancellable>() 或者我应该遍历集合并逐个取消所有订阅 for sub in bag { sub.cancel() } 苹果表示,在存储的AnyCancelable存储在内存中之前,订阅是有效的。因此,我想用bag.removeAll()释放可取消项就足够了,不是吗?尝试创建一个管道,不要将可取消项存储在某个状态变量中。您会发现管道在遇到异步操作时立即停止
private var bag = Set<AnyCancellable>()
或者我应该遍历集合并逐个取消所有订阅
for sub in bag {
sub.cancel()
}
苹果表示,在存储的AnyCancelable存储在内存中之前,订阅是有效的。因此,我想用
bag.removeAll()
释放可取消项就足够了,不是吗?尝试创建一个管道,不要将可取消项存储在某个状态变量中。您会发现管道在遇到异步操作时立即停止。这是因为可取消项被ARC清除,因此自动取消。因此,如果释放对管道的所有引用,则不需要调用管道上的cancel
从:
AnyCancelable实例在取消初始化时自动调用cancel()
我测试这个代码
let cancellable = Set<AnyCancellable>()
Timer.publish(every: 1, on: .main, in: .common).autoconnect()
.sink { print("===== timer: \($0)") }
.store(in: &cancellable)
cancellable.removeAll() // just remove from Set. not cancellable.cancel()
let cancelable=Set()
Timer.publish(每隔:1,在:.main上,在:.common中)。自动连接()
.sink{print(“=======计时器:\($0)”)}
.store(位于:&可取消)
cancelable.removeAll()//只需从集合中删除即可。不可取消。取消()
所以我使用这个扩展
import Combine
typealias CancelBag = Set<AnyCancellable>
extension CancelBag {
mutating func cancelAll() {
forEach { $0.cancel() }
removeAll()
}
}
导入联合收割机
typealias CancelBag=集
扩展取消包{
变异func cancelAll(){
forEach{$0.cancel()}
removeAll()
}
}
在deinit
上,您的ViewController将从内存中删除。它的所有实例变量都将被释放
Combine>Publisher>assign(to:on:)
的文档说:
可取消的实例。如果没有,请对此实例调用cancel()
不再希望发布者自动分配属性。
取消初始化此实例也将取消自动分配
1-我应该取消Denit中的订阅吗?还是自动完成任务?
你不需要,它会自动完成任务。当ViewController解除分配时,实例变量bag
也将解除分配。由于不再引用您的任何可取消的
,分配将结束
2-如果是,我如何取消所有存储的订阅?
不是这样。但通常情况下,您可能需要启动和停止一些订阅,例如,viewwillbeen
/viewdissapear
。在这种情况下,ViewController仍在内存中
因此,在viewdissummeed
中,您可以根据自己的想法执行bag.removeAll()
。这将删除引用并停止分配
下面是一些代码,您可以运行这些代码来查看.removeAll()
的操作:
var bag = Set<AnyCancellable>()
func testRemoveAll() {
Timer.publish(every: 1, on: .main, in: .common).autoconnect()
.sink { print("===== timer: \($0)") }
.store(in: &bag)
Timer.publish(every: 10, on: .main, in: .common).autoconnect()
.sink { _ in self.bag.removeAll() }
.store(in: &bag)
}
var bag=Set如果您碰巧从视图控制器订阅了一个发布者,您很可能会在sink
中捕获self
,这将对其进行引用,并且不会让ARC在订阅者未完成时删除您的视图控制器,因此,建议弱捕获self
因此,不是:
["title"]
.publisher
.sink { (publishedValue) in
self.title.text = publishedValue
}
.store(in: &cancellable)
您应该使用[弱自我]
:
["title"]
.publisher
.sink { [weak self] (publishedValue) in
self?.title.text = publishedValue
}
.store(in: &cancellable)
因此,当视图控制器被移除时,您将不会有任何保留周期或内存泄漏。创建一个可取消的+扩展。swift
import Combine
typealias DisposeBag = Set<AnyCancellable>
extension DisposeBag {
mutating func dispose() {
forEach { $0.cancel() }
removeAll()
}
}
它似乎不像文档所说的那样以这种方式工作。我测试了syncRequest().sink().store(in:&disposables),并在viewmodel上定义了它,并将deinit{}添加到视图模型中。Denit每次切换屏幕时都会打印,但subscription receiveCancel不是call,receiveValue是multipletimes@MichałZiobro听起来是stackoverflow的一个好问题:Dsubscriptions.removeAll()
在Swift 5.4中工作得很好,我想你的意思是“从集合中删除”而不是“数组”这是如何回答他的问题的?@giorashc user问他是应该手动取消订阅还是“它自动完成任务”,我的回答显示了如果没有任何对self的强烈引用,你如何避免考虑订阅。使用这种方式,订阅将自动删除。为什么要为集合中的每个AnyCancelable
显式调用cancel
?只要调用removeAll()
就足以将它们设置为零并取消正在进行的订户任务。
import Combine
typealias DisposeBag = Set<AnyCancellable>
extension DisposeBag {
mutating func dispose() {
forEach { $0.cancel() }
removeAll()
}
}
import Combine
import Foundation
final class CurrentWeatherViewModel: ObservableObject {
@Published private(set) var dataSource: CurrentWeatherDTO?
let city: String
private let weatherFetcher: WeatherFetchable
private var disposables = Set<AnyCancellable>()
init(city: String, weatherFetcher: WeatherFetchable = WeatherNetworking()) {
self.weatherFetcher = weatherFetcher
self.city = city
}
func refresh() {
disposables.dispose()
weatherFetcher
.currentWeatherForecast(forCity: city)
.map(CurrentWeatherDTO.init)
.receive(on: DispatchQueue.main)
.sink(receiveCompletion: { [weak self] value in
guard let self = self else { return }
switch value {
case .failure:
self.dataSource = nil
case .finished:
break
}
}, receiveValue: { [weak self] weather in
guard let self = self else { return }
self.dataSource = weather
})
.store(in: &disposables)
}
}