![](/img/trans.png)
[英]How to use Combine's CurrentValueSubject and access it in a SwiftUI View?
[英]How to use Combine on a SwiftUI View
这个问题与此有关: 如何使用SwiftUI和Combine观察TextField的值?
但是我要问的是比较笼统的。 这是我的代码:
struct MyPropertyStruct {
var text: String
}
class TestModel : ObservableObject {
@Published var myproperty = MyPropertyStruct(text: "initialText")
func saveTextToFile(text: String) {
print("this function saves text to file")
}
}
struct ContentView: View {
@ObservedObject var testModel = TestModel()
var body: some View {
TextField("", text: $testModel.myproperty.text)
}
}
场景:随着用户在文本字段中键入内容,应该调用saveTextToFile函数。 由于这是保存到文件,因此应放慢/限制它。
所以我的问题是:
我想在这里使用响应作为以下常规模式: 我们应该如何处理SwiftUI应用程序(而非UIKit应用程序)中的组合内容。
您应该在ViewModel
。 您的视图模型是TestModel
类(建议您在TestViewModel
重命名)。 在这里应该将逻辑放在模型和视图之间。 ViewModel
应该准备好模型以便进行可视化。 这是放置合并逻辑的正确位置(当然,如果它与视图有关)。
现在,我们可以使用您的特定示例来实际创建一个示例。 老实说,根据您真正想要实现的目标,有几种稍微不同的解决方案。 但是现在,我将尝试尽可能通用一些,然后您可以告诉我解决方案是否完善或需要一些改进:
struct MyPropertyStruct {
var text: String
}
class TestViewModel : ObservableObject {
@Published var myproperty = MyPropertyStruct(text: "initialText")
private var canc: AnyCancellable!
init() {
canc = $myproperty.debounce(for: 0.5, scheduler: DispatchQueue.main).sink { [unowned self] newText in
let strToSave = self.cleanText(text: newText.text)
if strToSave != newText.text {
//a cleaning has actually happened, so we must change our text to reflect the cleaning
self.myproperty.text = strToSave
}
self.saveTextToFile(text: strToSave)
}
}
deinit {
canc.cancel()
}
private func cleanText(text: String) -> String {
//remove all the spaces
let resultStr = String(text.unicodeScalars.filter {
$0 != " "
})
//take up to 5 characters
return String(resultStr.prefix(5))
}
private func saveTextToFile(text: String) {
print("text saved")
}
}
struct ContentView: View {
@ObservedObject var testModel = TestViewModel()
var body: some View {
TextField("", text: $testModel.myproperty.text)
}
}
您应该将您自己的subscriber
附加到TextField
publisher
并使用debounce
发布者来延迟字符串的清理和对save方法的调用。 根据文档:
反跳(用于:调度:选择:)
当您要等待上游发布者传递事件的暂停时,请使用此运算符。 例如, 在 发布者上从文本字段 调用反跳操作 以仅在用户暂停或停止键入时接收元素 。 当他们再次开始键入时,防跳动将保持事件传递直到下一个暂停。
当用户停止键入时,防反弹发布者将等待指定的时间(在我的示例中为0.5秒以上),然后使用新值调用其订阅者。
以上的延迟解决方案的字符串既节约和 TextField
更新。 这意味着在更新发生之前,用户会看到原始字符串(带有空格且可能超过5个字符的字符串)一段时间。 这就是为什么在这个答案的开头,我说根据需要有几种不同的解决方案。 如果确实确实要延迟字符串的保存,但是我们希望禁止用户输入空格字符或长度超过5个字符的字符串,则可以使用两个订阅者(我将仅发布更改的代码,即TestViewModel
类):
class TestViewModel : ObservableObject {
@Published var myproperty = MyPropertyStruct(text: "initialText")
private var saveCanc: AnyCancellable!
private var updateCanc: AnyCancellable!
init() {
saveCanc = $myproperty.debounce(for: 0.5, scheduler: DispatchQueue.main)
.map { [unowned self] in self.cleanText(text: $0.text) }
.sink { [unowned self] newText in
self.saveTextToFile(text: self.cleanText(text: newText))
}
updateCanc = $myproperty.sink { [unowned self] newText in
let strToSave = self.cleanText(text: newText.text)
if strToSave != newText.text {
//a cleaning has actually happened, so we must change our text to reflect the cleaning
DispatchQueue.main.async {
self.myproperty.text = strToSave
}
}
}
}
deinit {
saveCanc.cancel()
updateCanc.cancel()
}
private func cleanText(text: String) -> String {
//remove all the spaces
let resultStr = String(text.unicodeScalars.filter {
$0 != " "
})
//take up to 5 characters
return String(resultStr.prefix(5))
}
private func saveTextToFile(text: String) {
print("text saved: \(text)")
}
}
import Combine
struct MyPropertyStruct {
var text: String
}
class TestViewModel : ObservableObject {
@Published var myproperty = MyPropertyStruct(text: "initialText")
private var canc: AnyCancellable!
init() {
canc = $myproperty
.debounce(for: 0.5, scheduler: DispatchQueue.main)
.map { $0.text.replacingOccurrences(of: " ", with: "")}
.map { String($0.prefix(5)) }
.sink { [unowned self] strToSave in
self.saveTextToFile(text: strToSave)
}
}
private func saveTextToFile(text: String) {
print("text saved")
}
}
struct ContentView: View {
@ObservedObject var testModel = TestViewModel()
var body: some View {
TextField("", text: $testModel.myproperty.text)
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.