在 SwiftUI 中捕获绑定的最后一次更改 / 组合
Posted
技术标签:
【中文标题】在 SwiftUI 中捕获绑定的最后一次更改 / 组合【英文标题】:Capture the Very Last Change of a Binding in SwiftUI / Combine 【发布时间】:2021-03-10 05:44:52 【问题描述】:当我在 SwiftUI 中有一个绑定并且我想在绑定更改时保存(例如在 TextField 上)
var myText: String /* value is derived */
func save(_ text: String) /* doing the save stuff */
TextFiel(text: .init(get: myText , set: save($0) )
这样做,save()
会在绑定发生变化时被调用。在某些情况下,这可能并不理想,例如当 save() 进行服务器调用或一些昂贵的计算时。所以我正在寻找的是,每当最后一次的绑定发生变化时,我都会收到通知。
也许某种延迟的观察者会在最终更改后 x 秒触发,如果另一个更改发生在该阈值之前,则会失效。 Combine 是否提供这样的服务?
免责声明:这个问题是关于一般的绑定,而不仅仅是关于 TextFields。 Textfield 只是一个编码示例,所以.onCommit
不是我正在寻找的解决方案;)
【问题讨论】:
【参考方案1】:Combine 中的debounce
运算符执行此操作。它会等到一个新值没有通过管道推送 X 时间,然后发送一个信号。
在TextField
的情况下,您仍然需要“正常”绑定,因为您希望用户看到实时出现的字符,即使数据没有发送到服务器(或任何其他昂贵的操作)立即。
import Combine
import SwiftUI
class ViewModel : ObservableObject
@Published var text : String = ""
private var cancellables = Set<AnyCancellable>()
init()
$text
.debounce(for: .seconds(2), scheduler: RunLoop.main)
.sink (newValue) in
//do expensive operation
print(newValue)
.store(in: &cancellables)
struct ContentView : View
@StateObject var vm = ViewModel()
var body: some View
TextField("", text: $vm.text)
.textFieldStyle(RoundedBorderTextFieldStyle())
.padding()
根据您的操作,您可能还需要添加.receive(on:)
运算符。要更新 UI,您需要在主线程上接收。但是,对于其他昂贵的操作,您可以通过这种方式将内容发送到后台队列。
【讨论】:
去抖动是我所寻找的 100%。谢谢!以上是关于在 SwiftUI 中捕获绑定的最后一次更改 / 组合的主要内容,如果未能解决你的问题,请参考以下文章
iOS 15 SwiftUI 3 Picker 绑定在更改@State 值后不起作用
为啥我的绑定 [String] 不会更改我的多选列表 SwiftUI