【问题标题】:Why dosent my tableview show search results?为什么我的 tableview 不显示搜索结果?
【发布时间】:2019-06-04 07:59:19
【问题描述】:

我只在用户输入至少 2 个单词时才尝试完成对其他用户的搜索,然后才开始在数据库中搜索(因为我不想为用户扫描整个数据库)。我在搜索 2 个字母时遇到了一些问题,但我想我得到了代码(感谢用户 Jay)。

但是,当我在模拟器中运行它时,控制台会打印名称,但 tableview 中没有显示任何内容? (它是空的)。

你知道我做错了什么吗?

这是我的代码:

class FollowUsersTableViewController: UIViewController {

    @IBOutlet var tableView: UITableView!

    private var viewIsHiddenObserver: NSKeyValueObservation?
    let searchController = UISearchController(searchResultsController: nil)
    var usersArray = [UserModel]()
    var filteredUsers = [UserModel]()
    var loggedInUser: User?
    //
    var databaseRef = Database.database().reference()
    //usikker på den koden over

    override func viewDidLoad() {

        super.viewDidLoad()

        searchController.searchBar.delegate = self


        //large title
        self.title = "Discover"
        if #available(iOS 11.0, *) {
            self.navigationController?.navigationBar.prefersLargeTitles = true
        } else {
            // Fallback on earlier versions
        }

        self.tableView?.delegate = self
        self.tableView?.dataSource = self
        searchController.searchResultsUpdater = self
        searchController.dimsBackgroundDuringPresentation = false
        self.searchController.delegate = self;



        definesPresentationContext = true
        tableView.tableHeaderView = searchController.searchBar



    }

    func searchUsers(text: String) {
        if text.count >= 2 {
            self.usersArray = [] //clear the array each time
            let endingText = text + "\u{f8ff}"
            databaseRef.child("profile").queryOrdered(byChild: "username")
                .queryStarting(atValue: text)
                .queryEnding(atValue: endingText)
                .observeSingleEvent(of: .value, with: { snapshot in

                    for child in snapshot.children {
                        let childSnap = child as! DataSnapshot
                        print(childSnap)
                        let userObj =  Mapper<UserModel>().map(JSONObject: childSnap.value!)
                        userObj?.uid = childSnap.key
                        if childSnap.key != self.loggedInUser?.uid { //ignore this user
                            self.usersArray.append(userObj!)

                        }
                    }
                    self.tableView.reloadData()
                })
        }
    } //may need an else statement here to clear the array when there is no text


    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        let dest = segue.destination as! UserProfileViewController
        let obj = sender as! UserModel
        let dict = ["uid": obj.uid!, "username": obj.username!, "photoURL": obj.photoURL, "bio": obj.bio]
        dest.selectedUser = dict as [String : Any]
    }





}

// MARK: - tableview methods
extension FollowUsersTableViewController: UITableViewDataSource, UITableViewDelegate {



    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return searchController.searchBar.text!.count >= 2 ? filteredUsers.count : 0
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! FollowTableViewCell

        let user = filteredUsers[indexPath.row]

        cell.title?.text = user.username
        if let url = URL(string: user.photoURL ?? "") {
            cell.userImage?.sd_setImage(with: url, placeholderImage: #imageLiteral(resourceName: "user_male"), options: .progressiveDownload, completed: nil)
            cell.userImage.sd_setIndicatorStyle(.gray)
            cell.userImage.sd_showActivityIndicatorView()
        }

        return cell
    }

    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return 50
    }

    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        self.performSegue(withIdentifier: "user", sender: self.filteredUsers[indexPath.row])
    }



}

// MARK: - search methods
extension FollowUsersTableViewController:UISearchResultsUpdating, UISearchControllerDelegate, UISearchBarDelegate {



    func updateSearchResults(for searchController: UISearchController) {
        searchController.searchResultsController?.view.isHidden = false

        self.searchUsers(text: self.searchController.searchBar.text!)

        filterContent(searchText: self.searchController.searchBar.text!)

        self.tableView.reloadData()
    }

    func filterContent(searchText:String){

        if searchText.count >= 2{


            self.filteredUsers = self.usersArray.filter{ user in
                return(user.username!.lowercased().contains(searchText.lowercased()))
            }
        }
    }


}

【问题讨论】:

    标签: swift firebase firebase-realtime-database tableview uisearchbar


    【解决方案1】:

    这段代码非常接近,正如另一个答案指出的那样,您有两个数组。

    但让我们真正简化问题:您只需要一个数组,因为您要过滤 Firebase,而不是数组。

    换句话说,当用户在 searchField 中键入内容时,您正在向 Firebase 查询结果并将它们放入一个数组中。 这是您应该用作 tableView 的数据源的同一数组。

    当您的代码放置时,您正在过滤 Firebase,然后再次过滤那些不需要的结果。

    所以在高层次上假设我们的数据库中有四个用户

    Larry
    Moe
    Monroe
    Curly
    

    用户在搜索字段中输入“Mo”,这会导致您的 Fire 查询执行。它将返回两个结果:

    Mo
    Monroe
    

    然后将其填充到一个数组中 - 我们称之为 userResultsArray。

    然后

    tableView.reloadData()
    

    然后调用 tableView 委托方法

    func tableView(_ tableView: UITableView, numberOfRowsInSection
       return userResultsArray.count
    

    和

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath)
       get the user from userResultsArray
       return the user name
    

    如图所示,您只需要单个数组来存储来自 Firebase 的查询(过滤)结果。

    【讨论】:

    • 再次感谢杰,解释得很好。但是我按照 Sh_Khan 所说的做了,现在搜索可以工作了,但是我有两个问题: 1. 如果我输入两个以上的单词,它将重新加载数据并在两个 tableview 单元格中显示“Makelele”。 2. 搜索仅适用于具有大写首字母的用户名,并且不显示所有其他用户(具有小写用户名)。你知道怎么回事吗?
    • 另外,在我搜索了一个用户并取消了搜索(在搜索栏)之后,配置文件仍然在 tableview 中。
    • @MattGilbert 该解决方案不能直接解决您的问题或问题中的代码。无论如何,这都没有错,但与您的问题完全不同,这是一个完全不同的方向和解决方案。如果您想加载 所有 用户并在代码中进行过滤,那么这是一个完美的选择。但是,如果您有成千上万的用户,它可能会使设备不堪重负。如果您正在使用查询(如代码中所述),那不是问题。这取决于你想往哪个方向走。 a) 加载所有用户并在代码中过滤或 b) 使用查询来限制和返回结果。
    • 事情只是在寻找一种在我的 Firebase 数据库中为我的社交媒体应用程序搜索用户的方法。如果我的应用程序中有很多用户,我不想获得巨额的火力账单,所以我依靠一种很好的方式来进行查询。我当前的带有 Sh_Khan 输入的代码会以最好的方式做到这一点吗?
    • @MattGilbert 不。该代码依赖于加载所有用户并在代码中过滤。话虽如此,对于这种类型的解决方案来说,这是一个很好的答案,并且应该考虑的是,一旦您加载了用户,就不必再次加载它们,因此执行查询会更频繁地访问 Firebase,但您会限制数据每次击键都会返回。
    【解决方案2】:

    您有 2 个数组 usersArray 和 filteredUsers

    if childSnap.key != self.loggedInUser?.uid { //ignore this user
           self.usersArray.append(userObj!)
    }
    ...
     self.tableView.reloadData()
    

    所以上面的重新加载没有效果,因为你总是使用

    let user = filteredUsers[indexPath.row]
    

    在 cellForRowAt 中,在这种情况下你应该有一个类似的 var

    var isSearching = false
    

    然后在所有委托和数据源方法中搜索时更改它

     func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return isSearching ? filteredUsers.count : usersArray.count
     }
     func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! FollowTableViewCell
    
        let user = isSearching ? filteredUsers[indexPath.row] : usersArray[indexPath.row] 
      .....
     }
    
    func searchBarTextDidBeginEditing(_ searchBar: UISearchBar) {
        isSearching = true
    }
    
    func searchBarTextDidEndEditing(_ searchBar: UISearchBar) {
        isSearching = false
    }
    
    func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
        isSearching = false
    }
    
    func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
        isSearching = false
    }
    
    func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
    
        filteredUsers = usersArray.filter { /* do filter */ }
    
        if(filteredUsers.count == 0){
            isSearching = false
        } else {
            isSearching = true
        }
        self.tableView.reloadData()
    }
    
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        self.performSegue(withIdentifier: "user", sender: isSearching ? self.filteredUsers[indexPath.row] : self.usersArray[indexPath.row])
    }
    

    【讨论】:

    • 您好,感谢您的回答。但是我不太确定我明白你的意思,你能澄清一下吗?
    • 好吧,我看的更清楚一点,isSearching 的想法很好。但是你想让我用我的函数“func filterContent”做什么?因为我们在 textDidchange 中进行过滤
    • 我认为您需要将其替换为调用searchUsers
    • 我添加了这个self.filteredUsers = self.usersArray.filter{ user in return(user.username!.lowercased().contains(searchText.lowercased()))
    • 到你的 /* 做过滤器 */
    猜你喜欢
    • 1970-01-01
    • 2019-10-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多