此时,我们希望可以透过query的方式将db里的用户都显示出来。
因此今天将着重存在db的资料结构调整。
现在db里的结构如下
但是想要做到搜寻,我们没办法使用no-sql的资料结构去一个个找key。因此在此我们要修改一下资料结构。
思考一下对话的资料结构可能的样貌,由於我们想要保留每个已存在的对话可以被显示在conversation table view当中,因此每个使用者都会有自己的user array。
/*
[
[
"name": ,
"safe_email
],
[
"name": ,
"safe_email
],
]
*/
当我们新增(注册)一个使用者时,在insertUser
新增以下的内容
我们检查当下是否有以这个帐号为key的array
self.ref.child("users").observeSingleEvent(of: .value, with: { snapshot in
有的话就append、没有的话就新增。
if var usersCollection = snapshot.value as? [[String: String]] {
// append to user dictionary
let newElement = [
"name": user.firstName + " " + user.lastName,
"email": user.safeEmail
]
usersCollection.append(newElement)
self.ref.child("users").setValue(usersCollection, withCompletionBlock: { error , _ in
guard error == nil else {
completion(false)
return
}
completion(true)
})
} else {
let newCollection: [[String: String]] = [
[ "name": user.firstName + " " + user.lastName,
"email": user.safeEmail
]
]
self.ref.child("users").setValue(newCollection, withCompletionBlock: { error , _ in
guard error == nil else {
completion(false)
return
}
completion(true)
})
}
})
completion(true)
然後我们接下来想要做的是,如果现在手边有all user就直接filter,没有的话就先fetch再filter。
因此我们先宣告会使用到的东西。
在此result
是filter後的结果,而hasFetched
则是一个开关。
private let spinner = JGProgressHUD(style: .dark)
private var users = [[String: String]]()
private var results = [[String: String]]()
private var hasFetched = false
接着就是将刚刚提到的逻辑实作出来,我们使用replacingOccurrences
确保query的内容已经被trim过。
extension NewConversationViewController: UISearchBarDelegate {
func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
guard let text = searchBar.text, !text.replacingOccurrences(of: " ", with: "").isEmpty else {
return
}
results.removeAll()
spinner.show(in: view)
self.searchUsers(query: text)
}
拿到处理好的query後,开始从db比对。
func searchUsers(query: String) {
// check if array has firebase result
if hasFetched {
self?.filterUsers(with: query)
} else {
// fetch then filter
DatabaseManager.shared.getAllUsers(completion: { [weak self] result in
switch result {
case .success(let usersCollection):
self?.users = usersCollection
self?.filterUsers(with: query)
case .failure(let error):
print("Fail to get user: \(error)")
}
})
}
}
func filterUsers(with term: String){
// update the UI
guard hasFetched else {
return
}
let results: [[String: String]] = self.users.filter {
guard let name = $0["name"]?.lowercased() else{
return false
}
return name.hasPrefix(term.lowercased())
}
self.results = results
updateUI()
}
最後将结果显示出来,如果有结果就将tableView刷新显示;没有的话就显示noResult
的label。而这两的内容都已经有再先前写好了!
func updateUI() {
if results.isEmpty {
self.noResultLabel.isHidden = false
self.tableView.isHidden = true
} else {
self.noResultLabel.isHidden = true
self.tableView.isHidden = false
self.tableView.reloadData()
}
}
}
最後我们在Load进来的时候把subview都加进来
view.addSubview(noResultLabel)
view.addSubview(tableView)
tableView.delegate = self
tableView.dataSource = self
当然也别忘了跟随着tableView.delegate
以及tableView.dataSource
的extension。
extension NewConversationViewController: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return results.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = results[indexPath.row]["name"]
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
// start conversation
}
}
留了一个小伏笔,在didSelectRowAt
方法中,也就是当点选某个row,即代表开始展开对话~
终於要开始实作这30天的重点了吗(??)
若上述内容有误或可以改进的部分,欢迎留言以及提出任何指教~
谢谢 (´・∀・`)
>>: 【Day27】反馈元件 - Progress circle
CSS list-style 是提供网页调整列表清单中更多的显示功能,之前提到的HTML表单里有传统...
filter 眼尖的小光在昨日的内容中看到了一个有趣的东西,就是MiddlewareFilter,所...
main,dart: import 'package:firebase_core/firebase_...
中秋连假结束~ 参考线完成开始放入标题~ 把textview跟参考线连在一起~ 使用TextView...
今天就来完成登入验证的部分! 昨天已经完成发送帐号密码到api,验证ok即发送一笔JWT给clien...