#ios #swift #firebase #tableview #searchbar
#iOS #swift #firebase #просмотр таблицы #панель поиска
Вопрос:
Я настроил tableview, который извлекает данные из базы данных firebase в реальном времени и сохраняет эти данные в массиве (‘posts’) в таком формате:
(имя: nil, contactEmail: необязательно («35345345235»), contactPhoneNum: необязательно(«contact@gmail.com «), возраст: необязательно («25»), пол: ноль, последнее просмотренное: ноль, описание профиля: ноль)
Я хочу реализовать панель поиска для фильтрации значения имени записей и возврата записей, которые содержат искомое имя в tableview, и не уверен, как это сделать.
Вот мой код:
import UIKit
import Firebase
import FirebaseDatabase
import SwiftKeychainWrapper
import FirebaseAuth
class FeedVC: UITableViewController, UISearchBarDelegate{
@IBOutlet weak var searchBar: UISearchBar!
var currentUserImageUrl: String!
var posts = [postStruct]()
var selectedPost: Post!
var filteredPosts = [postStruct]()
override func viewDidLoad() {
super.viewDidLoad()
getUsersData()
getPosts()
searchBar.delegate = self
// Do any additional setup after loading the view.
// tableView.register(PostCell.self, forCellReuseIdentifier: "PostCell")
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func getUsersData(){
guard let userID = Auth.auth().currentUser?.uid else { return }
Database.database().reference().child("users").child(userID).observeSingleEvent(of: .value) { (snapshot) in
if let postDict = snapshot.value as? [String : AnyObject] {
self.tableView.reloadData()
}
}
}
struct postStruct {
let name : String!
let contactEmail : String!
let contactPhoneNum : String!
let age : String!
let gender : String!
let lastSeen : String!
let profileDescription : String!
}
func getPosts() {
let databaseRef = Database.database().reference()
databaseRef.child("firstName").queryOrderedByKey().observe( .childAdded, with: {
snapshot in
let name = (snapshot.value as? NSDictionary)!["name"] as? String
let contactEmail = (snapshot.value as? NSDictionary
)!["contactEmail"] as? String
let contactPhoneNum = (snapshot.value as? NSDictionary
)!["contactPhoneNum"] as? String
let age = (snapshot.value as? NSDictionary
)!["age"] as? String
let gender = (snapshot.value as? NSDictionary
)!["gender"] as? String
let lastSeen = (snapshot.value as? NSDictionary
)!["lastSeen"] as? String
let profileDescription = (snapshot.value as? NSDictionary
)!["profileDescription"] as? String
self.posts.append(postStruct(name: name,contactEmail:contactEmail, contactPhoneNum:contactPhoneNum, age:age, gender:gender, lastSeen:lastSeen, profileDescription:profileDescription))
DispatchQueue.main.async {
self.tableView.reloadData()
}
})
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
print("posts count = ", filteredPosts.count)
return filteredPosts.count
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
// tableView.dequeueReusableCell(withIdentifier: "PostCell")!.frame.size.height
return 230
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "PostCell") as? PostCell else { return UITableViewCell() }
cell.nameLabel?.text = filteredPosts[indexPath.row].name
cell.contactEmailLabel?.text = filteredPosts[indexPath.row].contactEmail
cell.contactPhoneNumLabel?.text = filteredPosts[indexPath.row].contactPhoneNum
cell.ageLabel?.text = filteredPosts[indexPath.row].age
cell.genderLabel?.text = filteredPosts[indexPath.row].gender
cell.lastSeenLabel?.text = filteredPosts[indexPath.row].lastSeen
cell.profileDescriptionLabel?.text = filteredPosts[indexPath.row].profileDescription
print(filteredPosts)
return cell
}
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
filteredPosts = posts.filter { $0.name?.lowercased().contains(searchText.lowercased()) == true }
}
}
Комментарии:
1. Требуется некоторое уточнение; Вы хотите загружать каждую запись данные в память из Firebase и сохранять их все в массиве, а затем фильтровать это? Или вы хотите запросить данные firebase и вернуть только это подмножество данных? Это важно, поскольку, если у вас миллион записей, вы перегрузите устройство загрузкой всего этого. Кроме того, ваш массив содержит только ‘name’ (как в строке) или он содержит всю ‘post’?
2. Извините, я довольно новичок в firebase. Я хочу выполнить поиск по «имени» каждой записи, чтобы вернуть совпадающие имена, поэтому я не уверен, какой подход выбрать. Массив ‘posts’ содержит все данные post, сохраненные как postStruct (формат, показанный выше).
3. Вам нужно будет принять решение, поскольку подход сильно отличается. Если у вас много записей, это может перегрузить устройство, как упоминалось, но если вы запрашиваете firebase, вам потребуется вернуть только подмножество данных.
4. На самом деле это не плохой вопрос — просто нужна некоторая ясность, выполняет ли OP поиск по массиву или Firebase. Проголосовали за повторное открытие
5. Я бы предпочел запрашивать firebase для имен
Ответ №1:
Зацикливание на posts
предоставит элемент типа Post
not String
. Вот исправление:
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
filteredPosts = []
for post in posts {
if post.name?.lowercased().contains(searchText.lowercased()) == true {
filteredPosts.append(post)
}
}
}
Или просто используйте метод более высокого порядка, такой filter
как вдохновленный комментарием @ Jay.
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
filteredPosts = posts.filter { $0.name?.lowercased().contains(searchText.lowercased()) == true }
}
Комментарии:
1. @maya В опубликованном ответе нет ничего плохого, кроме расширенных циклов, которых следует избегать. Это немного короче
let filteredResults = posts.filter { $0.name.lowercased() == "string you're searching for".lowercased() }
2. @Jay Я даже не знаю, почему я добавил дополнительный цикл в свой ответ. Я внес несколько изменений в ваше предложение, например, нам не нужно объявлять новую переменную,
filteredResults
которой мы могли бы напрямую назначить результат,filteredPosts
также содержит поиск и необязательноеname
свойство :).3. @Jay Я изменил свой код, чтобы включить это (см. Редактирование), но в filteredResults нет никаких значений: print(filteredPosts.count) возвращает количество записей = 0
4. @maya Смотрите комментарии к вопросу, но если вам нужна помощь, вам нужно выполнить дополнительные действия по устранению неполадок. Например, действительно ли массив posts содержит какие-либо данные? Действительно ли вызывается функция делегирования при вводе текста? Вы добавили точку останова и проверяли переменные по мере ввода? Каков же был результат? Видите — мы не можем сделать это за вас, но базовое устранение неполадок может выявить причину и предоставит более точную информацию для включения в вопрос, чтобы нам было, над чем работать. Прямо сейчас — мы просто предполагаем.