视图消失时如何使用组合框架取消初始化 ViewModel

How to deinit ViewModel with combine framework when views disappears

我在 viewModels 中使用 Combine 来更新视图。但是,如果我将 AnyCancellable 对象存储到一组 AnyCancellable 中,则永远不会调用 deinit 方法。我使用 deinit 来取消所有可取消对象。

struct View1: View {

    @ObservedObject var viewModel:ViewTextModel = ViewTextModel()
    @Injected var appActions:AppActions

    var body: some View {
        VStack {
            Text(self.viewModel.viewText)

            Button(action: {
                self.appActions.goToView2()
            }) {
                Text("Go to view \(self.viewModel.viewText)")
            }
        }
    }
}
class ViewTextModel: ObservableObject {
    @Published var viewText: String

    private var cancellables = Set<AnyCancellable>()

    init(state:AppState) {
        // initial state
        viewText = "view  \(state.view)"
        // updated state
        state.$view.removeDuplicates().map{ "view \([=11=])"}.assign(to: \.viewText, on: self).store(in: &cancellables)
    }

    deinit {
        cancellables.forEach { [=11=].cancel() }
    } 
}

每次重建视图时,都会实例化一个新的视图模型,但不会破坏旧视图模型。 viewText 属性在每个实例上更新 state.$view.removeDuplicates().map{ "view \([=13=])"}.assign(to: \.viewText, on: self).store(in: &cancellables)

如果我不在集合中存储可取消对象,则会调用 deinit,但如果当前视图的状态已更改,则不会更新 viewText

你知道如何在不增加视图模型实例的情况下管理状态的更新吗?

谢谢

您可以使用 sink 而不是 assign:

state.$view
    .removeDuplicates()
    .sink { [weak self] in self?.viewText = [=10=] }
    .store(in: &cancellables)

但我完全质疑 Combine 的必要性。只需使用计算 属性:

class ViewTextModel: ObservableObject {
    @Published var state: AppState

    var viewText: String { "view \(state.view)" }
}

更新

如果您的部署目标是 iOS 14(或 macOS 11)或更高版本:

因为您要存储到 @Published,所以您可以改用 assign(to:) 运算符。它为您管理订阅而不返回 AnyCancellable.

state.$view
    .removeDuplicates()
    .map { "view \([=12=])" }
    .assign(to: &$viewText)
    // returns Void, so nothing to store