如何“转发”@Published 值

Posted

技术标签:

【中文标题】如何“转发”@Published 值【英文标题】:How to "forward" a @Published value 【发布时间】:2020-01-02 19:22:42 【问题描述】:

我对 SwiftUI 和 Combine 非常陌生,尽管我对 Swift 有丰富的经验,并且对 ReactiveKit 有一点经验,但我发现很难让一些基本的东西发挥作用。

例如,我试图在我的 ViewModel 上添加一个isLoggedIn 属性,它应该只是“转发”UserManager 类的isLoggedIn 属性。使用 ReactiveKit 这相当简单,但使用 SwiftUI/Combine 我无法工作。该值仅设置一次,然后不再更新。

class UserManager: ObservableObject 
  @Published private(set) var isLoggedIn = false

  // This class has all the actual logic for logging in, 
  // keeping track of the logged in user and the auth status, etc.


class ViewModel: ObservableObject 
  @Published var isLoggedIn = false

  private let userManager: UserManager

  init(userManager: UserManager) 
    self.userManager = userManager
    isLoggedIn = userManager.isLoggedIn // <- this doesn't work
    userManager.$isLoggedIn.assign(to: \.isLoggedIn, on: self) // <- neither does this
  

  func logout() 
    userManager.logout()
  


struct ContentView: View  
  @ObservedObject var viewModel: ViewModel

  var body: some View 
    // this will use viewModel.isLoggedIn at some point
  

【问题讨论】:

【参考方案1】:

以下应该有效。如果您不存储订阅者,它会自动取消。

  private var subscribers = [AnyCancellable]()
  init(userManager: UserManager) 
    self.userManager = userManager
    userManager.$isLoggedIn
       .assign(to: \.isLoggedIn, on: self)
       .store(in: &subscribers) // << subscriber must be kept
  

【讨论】:

谢谢,这很有道理。【参考方案2】:

另一种方法是将 ViewModel 中的 @Published var isLoggedIn 替换为手动 objectWillChange。

class ViewModel: ObservableObject 
  var isLoggedIn: Bool userManager.isLoggedIn

  private let userManager: UserManager
  private var anyCancellable: AnyCancellable?

  init(userManager: UserManager) 
    self.userManager = userManager

    anyCancellable = userManager.objectWillChange.sink [weak self] _ in
      self?.objectWillChange.send()
    
  


【讨论】:

以上是关于如何“转发”@Published 值的主要内容,如果未能解决你的问题,请参考以下文章

SwiftUI 如何将@Published 分配给另一个@Published

在主线程上使用 @Published 值?

SwiftUI 将@Published viewmodel 对象值传递给@Binding

结合@Published 属性:在更新期间从其他地方获取当前值

为啥在 SwiftUI ObservableObject 中没有触发 @Published 值?

是否所有 @Published 变量都需要在 SwiftUI 的视图模型中具有初始值?