Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ios/116.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
iOS Swift联合收割机:取消一套<;任何可取消的>;_Ios_Swift_Swiftui_Ios13_Combine - Fatal编程技术网

iOS Swift联合收割机:取消一套<;任何可取消的>;

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()释放可取消项就足够了,不是吗?尝试创建一个管道,不要将可取消项存储在某个状态变量中。您会发现管道在遇到异步操作时立即停止

如果我已将可取消集存储到ViewController中:

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的一个好问题:D
subscriptions.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)
    }
}