如何让TextField值更改触发对SwiftUI中另一条数据的更新?

如何让TextField值更改触发对SwiftUI中另一条数据的更新?,swiftui,combine,Swiftui,Combine,我正在尝试学习Swift、SwiftUI和Combine,我对iOS基本上是新手。最后,我希望有一个列表,您可以搜索、筛选和排序 到目前为止,当我在文本字段中使用onEditingChanged时,过滤工作正常,但这需要按enter键。当文本字段filterText更改时,我不知道如何触发activePeople更新,以便在键入时activePeople列表进行过滤 当我在视图中过滤ForEach中的列表时,我已经得到了一个版本可以工作(请参阅注释掉的代码),但最终过滤和排序将变得更加复杂,并且

我正在尝试学习Swift、SwiftUI和Combine,我对iOS基本上是新手。最后,我希望有一个列表,您可以搜索、筛选和排序

到目前为止,当我在文本字段中使用
onEditingChanged
时,过滤工作正常,但这需要按enter键。当文本字段
filterText
更改时,我不知道如何触发
activePeople
更新,以便在键入时
activePeople
列表进行过滤

当我在视图中过滤ForEach中的列表时,我已经得到了一个版本可以工作(请参阅注释掉的代码),但最终过滤和排序将变得更加复杂,并且将其置于该视图之外似乎更有意义。无论出于何种原因,如果这不是正确的方法,请告诉我

以下是迄今为止的代码:

import Combine
import SwiftUI

class Model: ObservableObject {
    @Published var filterText: String = “”
    @Published var activePeople: [Person] = []

    private var allPeople : [Person] = [
        Person( id: 1000, name: “Alexa” ),
        Person( id: 1001, name: “Anaïs” ),
        Person( id: 1002, name: “Earl” ),
        Person( id: 1003, name: “Elba” ),
        Person( id: 1004, name: "Emil” ),
        Person( id: 1005, name: “Janeth” ),
        Person( id: 1006, name: “Joselyn” ),
        Person( id: 1007, name: “Lupita” ),
        Person( id: 1008, name: “Mellie” ),
        Person( id: 1009, name: “Vanita” ),
    ]

    init() {
        activePeople = allPeople
    }

    func filterList() {
        if ( filterText == “” ) {
            activePeople = allPeople
        } else {
            activePeople = allPeople.filter( { $0.name.localizedStandardContains( filterText ) } )
        }
    }

}

struct Person: Identifiable {
    var id: Int
    var name: String
}


只需在ContentView中应用筛选:

ForEach(model.activePeople.filter({ self.model.filterText.isEmpty ||
                                   $0.name.localizedStandardContains(self.model.filterText)})) { person in
                            Text( person.name )
                    }

为了观察textfield输入的变化,您可以观察模型中的变量。从视图中删除过滤逻辑可能也是一个好主意。 例如,当模型初始化时,开始观察
filterText
。另外,请记住保留对从
sink
返回的可取消项的引用。 我们在这里要做的是,每当
filterText
中的值发生变化时(这是因为textfield绑定),我们将过滤数组,并为
activePeople
变量指定一个值

 var filterCancellable: AnyCancellable?

    init() {
        filterCancellable = $filterText.sink {[weak self] currentText in
            guard let strongSelf = self else { return } 
            strongSelf.activePeople = strongSelf.filterList(with: currentText)
        }
    }

    func filterList(with text: String) -> [Person] {
        if ( text == "" ) {
            return allPeople
        } else {
            return allPeople.filter( { $0.name.localizedStandardContains( text ) } )
        }
    }
这样你以后就可以做了

var body: some View {
        VStack {
            Form {
                Section {
                    TextField("Filter Text", text: $model.filterText)
                }
                Section {
                    Text( "Filtered by: \(model.filterText)" )
                    ForEach( model.activePeople ) { person in
                        Text( person.name )
                    }
                }
            }
        }
    }

有没有办法把它挡在视线之外?最后,我想使用多个过滤器并应用排序。在视图中保留所有这些逻辑是SwiftUI的工作方式吗?您可以将其移动到负责过滤数据的单独结构中。
var body: some View {
        VStack {
            Form {
                Section {
                    TextField("Filter Text", text: $model.filterText)
                }
                Section {
                    Text( "Filtered by: \(model.filterText)" )
                    ForEach( model.activePeople ) { person in
                        Text( person.name )
                    }
                }
            }
        }
    }