我尝试使用Algolia实现搜索栏,并使用MVVM模式。
这是我的视图模型:
class AlgoliaViewModel: ObservableObject {
@Published var idList = [String]()
func searchUser(text: String){
let client = SearchClient(appID: "XXX", apiKey: "XXX")
let index = client.index(withName: "Users")
let query = Query(text)
index.search(query: query) { result in
if case .success(let response) = result {
print("Response: \(response)")
do {
let hits: Array = response.hits
var idList = [String]()
for x in hits {
idList.append(x.objectID.rawValue)
}
DispatchQueue.main.async {
self.idList = idList
print(self.idList)
}
}
catch {
print("JSONSerialization error:", error)
}
}
}
}
}
这是我的观点:
struct NewChatView : View {
@State private var searchText = ""
@ObservedObject var viewModel = AlgoliaViewModel()
var body : some View{
VStack(alignment: .leading){
Text("Select To Chat").font(.title).foregroundColor(Color.black.opacity(0.5))
ScrollView(.vertical, showsIndicators: false) {
VStack(spacing: 12){
HStack {
TextField("Start typing",
text: $searchText,
onCommit: { self.viewModel.searchUser(text: self.searchText) })
.textFieldStyle(RoundedBorderTextFieldStyle())
Button(action: {
self.viewModel.searchUser(text: self.searchText)
}) {
Image(systemName: "magnifyingglass")
}
} .padding()
List {
ForEach(viewModel.idList, id: \.self){ i in
Text(i)
}
}
}
}
}.padding()
}
}
我经常在Firebase中使用这种模式,并且一切正常,但是在Algolia中,List
在NewChatView
中仍然为空。
视图模型内的print(self.idList)
语句显示正确的idList
,但不会更新List
内的NewChatView
。
答案 0 :(得分:2)
您首先需要创建自己的自定义Identifiable
和Hashable
模型,以在searchValue
或List
中显示ForEach
。
类似这样的东西:
struct MySearchModel: Identifiable, Hashable {
let id = UUID().uuidString
let searchValue: String
}
然后在您的AlgoliaViewModel
中使用它。设置一个空数组的默认值。
您还可以映射收到的hits
并将其转换为新模型。不需要多余的for
循环。
class AlgoliaViewModel: ObservableObject {
@Published var idList: [MySearchModel] = []
func searchUser(text: String) {
let client = SearchClient(appID: "XXX", apiKey: "XXX")
let index = client.index(withName: "Users")
let query = Query(text)
index.search(query: query) { result in
if case .success(let response) = result {
print("Response: \(response)")
do {
let hits: Array = response.hits
DispatchQueue.main.async {
self.idList = hits.map({ MySearchModel(searchValue: $0.objectID.rawValue) })
print(self.idList)
}
}
catch {
print("JSONSerialization error:", error)
}
}
}
}
}
对于NewChatView
,您可以删除ScrollView
,因为它与当前VStack
中的元素冲突,并且也将List
隐藏在结果中。以下更改应显示所有结果。
struct NewChatView : View {
@State private var searchText = ""
@ObservedObject var viewModel = AlgoliaViewModel()
var body: some View{
VStack(alignment: .leading) {
Text("Select To Chat")
.font(.title)
.foregroundColor(Color.black.opacity(0.5))
VStack {
HStack {
TextField("Start typing",
text: $searchText,
onCommit: { self.viewModel.searchUser(text: self.searchText)
})
.textFieldStyle(RoundedBorderTextFieldStyle())
Button(action: {
self.viewModel.searchUser(text: self.searchText)
}) {
Image(systemName: "magnifyingglass")
}
} .padding()
List {
ForEach(viewModel.idList) { i in
Text(i.searchValue)
.foregroundColor(Color.black)
}
}
}
}.padding()
}
}