SwiftUI:视图模型不更新视图

SwiftUI: View Model does not update the View

我尝试用 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 中,ListNewChatView.

中仍然为空

View-Model里面的print(self.idList)语句显示了正确的idList,但是它没有更新NewChatView里面的List

您首先需要创建自己的自定义 IdentifiableHashable 模型以在 ListForEach 中显示 searchValue

像这样:

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: [=11=].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()
    }
}