首页 > 解决方案 > 在从 Firebase DB 获取结果的 UITableView 上实现搜索

问题描述

我有一个UITableView从 Firebase 实时数据库获取数据的设备。我需要添加对列表的搜索,获取的数据属于名为Post. 一旦用户单击单元格,它将数据传递给详细视图控制器。搜索目前无法正常工作,因为它正在搜索 aNSDictionary而不是Post,我也不确定如何去做。

class PostTable: UIViewController, UITableViewDelegate, UITableViewDataSource, UISearchResultsUpdating {


func updateSearchResults(for searchController: UISearchController) {
    filterContentForSearchText(searchController.searchBar.text!)
    print(searchController.searchBar.text)
}

func searchBarIsEmpty() -> Bool {
    // Returns true if the text is empty or nil
    return searchController.searchBar.text?.isEmpty ?? true
}

func filterContentForSearchText(_ searchText: String) {
    print("Search Text = " + searchText)
    filteredPosts = filteredPosts.filter({( post : Post) -> Bool in
        print(post.title.title.lowercased().contains(searchText.lowercased()))
        return post.title.title.lowercased().contains(searchText.lowercased())
    })

    tableView.reloadData()
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{
    let cell = tableView.dequeueReusableCell(withIdentifier: "postCell", for: indexPath) as! PostTableViewCell
    cell.set(post: posts[indexPath.row])
    let user : Post

    if searchController.isActive && searchController.searchBar.text != "" {
        user = filteredPosts[indexPath.row]
    }
    else
    {
        cell.set(post: posts[indexPath.row])
    }
    return cell
}


@IBOutlet weak var scrollView: UIScrollView!

@IBOutlet weak var tableView: UITableView!

var searchActive : Bool = false

let searchController = UISearchController(searchResultsController: nil)
var posts = [Post]()

var filteredPosts = [Post]()



override func viewDidLoad() {
    super.viewDidLoad()

    if Auth.auth().currentUser == nil {
        switchStoryboard()
    }

    let cellNib = UINib(nibName: "PostTableViewCell", bundle: nil)
    tableView.register(cellNib, forCellReuseIdentifier: "postCell")
    var layoutGuide:UILayoutGuide!


    tableView.delegate = self
    tableView.dataSource = self
    tableView.tableFooterView = UIView()
    tableView.reloadData()

    searchController.searchResultsUpdater = self
    searchController.dimsBackgroundDuringPresentation = false
    definesPresentationContext = true
    tableView.tableHeaderView = searchController.searchBar

    observePosts()
}

func switchStoryboard() {
    DispatchQueue.main.async {
        let vc: UIViewController? = self.storyboard?.instantiateViewController(withIdentifier: "ViewController")
        var window: UIWindow? = (UIApplication.shared.delegate?.window)!
        window?.rootViewController = vc
    }
}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}

func observePosts() {
    let postsRef = Database.database().reference().child("Data").queryOrdered(byChild: "priority")
    print(postsRef)
    postsRef.observe(.value, with: { snapshot in
        var tempPosts = [Post]()

        for child in snapshot.children{

            if let childSnapshot = child as? DataSnapshot,
                let dict = childSnapshot.value as? [String:Any],
                let title = dict["title"] as? String,
                let logoImage = dict["image"] as? String,
                let url = URL(string:logoImage),
                let address = dict["address"] as? String,
                let contact = dict["contact"] as? String,
                let description = dict["description"] as? String{


                let userProfile = UserProfile(title: title, photoURL: url)
                let post = Post(id: childSnapshot.key, title: userProfile, description: description, image: userProfile, address: address, contact: contact)
                print(post)
                tempPosts.append(post)
            }
        }

        self.posts = tempPosts
        self.tableView.reloadData()
    })
}


func getImage(url: String, completion: @escaping (UIImage?) -> ()) {
    URLSession.shared.dataTask(with: URL(string: url)!) { data, response, error in
        if error == nil {
            completion(UIImage(data: data!))
        } else {
            completion(nil)
        }
        }.resume()
}

func numberOfSections(in tableView: UITableView) -> Int {
    return 1
}

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
   if searchController.isActive && searchController.searchBar.text != ""{
       return filteredPosts.count
   } else {
       return posts.count
   }
}

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    tableView.deselectRow(at: indexPath, animated: true)

    let postsInfo = posts[indexPath.row]
    print(postsInfo)

    let Storyboard = UIStoryboard(name: "Main", bundle: nil)
    let DvC = Storyboard.instantiateViewController(withIdentifier: "PostTableDetailed") as! PostTableDetailed
    DvC.getName = postsInfo.title.title
    DvC.getDesc = postsInfo.description
    DvC.getImg = postsInfo.title.photoURL.absoluteString
    DvC.getAddress = postsInfo.address
    DvC.getContact = postsInfo.contact

    self.navigationController?.pushViewController(DvC, animated: true)
}
}

标签: iosuitableview

解决方案


cellForRow是错的

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{
    let cell = tableView.dequeueReusableCell(withIdentifier: "postCell", for: indexPath) as! PostTableViewCell
    let post = searchController.isActive ? filteredPosts[indexPath.row] : posts[indexPath.row]
    cell.set(post: post)
    return cell
}

检查就足够了searchController.isActive


而且你必须过滤postsfilteredPosts。我还更改了的签名filterContentForSearchText以符合命名准则。

func filterContent(for searchText: String) {
    filteredPosts = posts.filter{ $0.title.range(of: searchText, options: .caseInsensitive) != nil }
    tableView.reloadData()
}

请注意,didSelectRowAt当它处于活动状态时可能会崩溃或导致意外行为searchController


推荐阅读