带有组合框架的按钮操作

Vya*_*lav 6 swift swiftui combine

为按钮操作事件实现响应式编程的最佳方法是什么?

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

我的意思是这样的:

@State var isVisible = false

....

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

....

if isVisible {
    Text("texty text")
}
Run Code Online (Sandbox Code Playgroud)

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

final class ViewModel {
    func pleaseDoAction() {
        mySubject.send("some")
    }
}
Run Code Online (Sandbox Code Playgroud)

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

Sco*_*ant 6

@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()
        })
    }
}

Run Code Online (Sandbox Code Playgroud)
  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)
        
    }
}
Run Code Online (Sandbox Code Playgroud)
  1. 游乐场中的用法示例:

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

let playgroundView = MyAwesomeView()
let playgroundExample = A(view: playgroundView)
PlaygroundPage.current.setLiveView(playgroundView)
Run Code Online (Sandbox Code Playgroud)


小智 2

两种方法:

  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("...")
  }
}
Run Code Online (Sandbox Code Playgroud)
  1. 利用出版商Combine
import Combine
import SwiftUI

final class ViewModel: ObservableObject {
   let objChanges = ObservableObjectPublisher() 

   var isVisible: Bool = false {
      willSet {
          objChanges.send()
      }
   }
}
Run Code Online (Sandbox Code Playgroud)

View第二个与第一个非常相似。

此外, Paul Hudson和 WWDC2019的经验教训可能会为上述包装器及其用法提供更多见解。