结合框架的按钮动作

时间:2019-11-10 20:43:20

标签: swift swiftui combine

为按钮动作事件实施反应式编程的最佳方法是什么?

关于指南和示例,我只找到了带有 SwiftUI @State的示例。

我的意思是这样的:

@State var isVisible = false

....

Button(action: {
    self.isVisible.toggle()
} 

....

if isVisible {
    Text("texty text")
}

但是,如果我想执行后台任务怎么办? 显而易见的方法是在viewModel?.pleaseDoAction()内调用Button.action(,并创建在pleaseDoAction()内部触发的自定义主题:

final class ViewModel {
    func pleaseDoAction() {
        mySubject.send("some")
    }
}

但这是 SwiftUI +合并的正确架构方法吗? 简而言之,按钮操作应该是发布者,但不是。

2 个答案:

答案 0 :(得分:1)

两种方法:

  1. 使用@Published
import SwiftUI

final class ViewModel: ObservableObject {

   @Published var isVisible = false 

}


struct SampleView: View {
  @ObservedObject var model = ViewModel()


  Button(action: {
     self.model.isVisible.toggle()
  }) {
     Text("...")
  }
}
  1. 利用Combine的发布者
import Combine
import SwiftUI

final class ViewModel: ObservableObject {

   let objChanges = ObservableOjbectPublisher() 

   var isVisible: Bool = false {
      willSet {
          objChanges.send()
      }
   }
}

第二个视图与第一个视图非常相似。

另外,Paul Hudson和WWDC2019的课程可能会提供有关上述包装及其用法的更多见解

答案 1 :(得分:1)

@Partha G的ViewModel方法可能是最合适的,但这是一种不需要视图模型的简单方法。

作为警告,如果您的视图这样做,则此方法可能无法很好地与SwiftUI视图刷新配合。但是对于这种非常简单的情况,它似乎运行良好。

  1. 将PassthroughSubject添加到您的视图中,如下所示:
// Your view with a button:

import SwiftUI
import Combine

struct MyAwesomeView: View {
    
    public var buttonPressedSubject = PassthroughSubject<Void, Never>()

    var body: some View {
        
        Button("Push This Button", action: {
            self.buttonPressedSubject.send()
        })
    }
}

  1. 订阅并使用该主题,如下所示:
import Combine

class A {
    
    private var cancelBag = Set<AnyCancellable>()
    
    private let myView: MyAwesomeView
    
    init(view: MyAwesomeView) {
        self.myView = view
        
        myView.buttonPressedSubject
            .sink { (_) in
                print("The button was pressed.")
        }
        .store(in: &cancelBag)
        
    }
}
  1. 在操场上的用法示例:

// <#Copy-paste code from above here#>
import PlaygroundSupport

let playgroundView = MyAwesomeView()
let playgroundExample = A(view: playgroundView)
PlaygroundPage.current.setLiveView(playgroundView)