【问题标题】:SwiftUI CurrentValueSubject BehaviorSwiftUI CurrentValueSubject 行为
【发布时间】:2021-12-30 04:08:03
【问题描述】:

我是 SwiftUI 的新手。我与 UIKit 和组合框架一起使用 ViewModel、UseCases 和 Repositories 构建架构。我所有的架构都是基于加载状态。我的加载状态是这样构建的:

/// Equivalent to @Published with `LoadingState<T, E>` property wrapper
@propertyWrapper public class Loading<T, E: Swift.Error> {
public typealias State = LoadingState<T, E>

public var wrappedValue: State {
    willSet {
        subject.send(newValue)
    }
}

public init(wrappedValue: State) {
    self.wrappedValue = wrappedValue
}

private lazy var subject = CurrentValueSubject<State, Never>(wrappedValue)

public var projectedValue: AnyPublisher<State, Never> {
    return subject.eraseToAnyPublisher()
}
}

我的 ViewModel 以这种方式工作:

@Loading<MyData, MyError> var myDataLoadingState = .idle
public func getMyData(ID: String) {
    myDataLoadingState = .loading
    
    myDataUseCase.execute(ID: ID)
        .receive(on: DispatchQueue.main)
        .sink { completion in
            guard case .failure(let error) = completion else { return }
            myDataLoadingState = .failure(error)
        } receiveValue: { myData in
            self. myDataLoadingState = .success(myData)
        }
        .store(in: &self.cancellables)
}

控制器是这样工作的:

viewModel.$myDataLoadingState
       .sink { state in
           switch state {
           case .idle:
            break
           case .loading:
             self.showLoader()
           case .success(let myData):
            print(myData)
           case .failure(let error):
            self.print(error)
            self.hideLoader()
           }
       }
       .store(in: &cancellables)

我可以在 SwiftUI 中使用加载状态和我的 ViewModel 吗?我尝试过这种方式但似乎不起作用:

struct ContentView: View {
@StateObject var viewModel: MyViewModel

var body: some View {
    switch viewModel.loadingState {
    case .idle:
        Text("Idle")
    case .loading:
        Text("Loading")
    case .success(let myData):
        Text(myData.name)
    case .failure(let error):
        Text(error.localizedDescription)
    }
}
}

ViewModel 现在是 ObservableObject

public class MyViewModel: ObservableObject {

}

提前致谢

【问题讨论】:

  • 你的myDataLoadingState@Published 包装吗?
  • 嗯没有。你能更好地解释一下吗?

标签: swift swiftui combine


【解决方案1】:

刚刚认识到您已经拥有myDataLoadingState 的属性包装器,因此不确定您是否可以改为使用@Published。无论如何,要通知 @StateObject 包装器(谁是听众),您应该触发有关视图模型更改的事件。一种可能的方法是直接使用objectWillChange,比如

myDataUseCase.execute(ID: ID)
    .receive(on: DispatchQueue.main)
    .sink { completion in
        guard case .failure(let error) = completion else { return }

        self.objectWillChange.send()             // << here !!
        myDataLoadingState = .failure(error)
    } receiveValue: { myData in
        self.objectWillChange.send()             // << here !!
        self.myDataLoadingState = .success(myData)
    }
    .store(in: &self.cancellables)

【讨论】:

  • 嗯好的,这是一个解决方案!谢谢!在您看来,有一种方法可以不编辑每个视图模型并直接使用我的加载状态?
  • 没有。我不知道你为什么需要它,实际上所有需要的是@Published var myDataLoadingState
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-06-14
  • 2020-02-28
  • 2021-04-16
  • 1970-01-01
  • 1970-01-01
  • 2021-02-09
  • 2021-06-13
相关资源
最近更新 更多