在 UICollectionViewController (Swift 4) 中实现 UISearchBarController?

Posted

技术标签:

【中文标题】在 UICollectionViewController (Swift 4) 中实现 UISearchBarController?【英文标题】:Implement UISearchBarController within UICollectionViewController (Swift 4)? 【发布时间】:2018-03-22 17:33:39 【问题描述】:

我正在尝试在 UICollectionViewController 中实现 UISearchBarController,代码如下:

    class FirstViewController: UICollectionViewController, UICollectionViewDelegateFlowLayout, UISearchResultsUpdating 

         var titles: [String] = []

         var card: [RecommendArticles]?

         var searchArr = [String]()
            didSet 
               self.collectionView?.reloadData()
        
    

        func updateSearchResults(for searchController: UISearchController) 

            guard let searchText = searchController.searchBar.text else 
                return
            

            searchArr = titles.filter  (title) -> Bool in
                return title.contains(searchText)
            


        


        let searchController = UISearchController(searchResultsController: nil)

       override func viewDidLoad() 

        super.viewDidLoad()

        searchController.searchResultsUpdater = self
        searchController.dimsBackgroundDuringPresentation = false
        navigationItem.hidesSearchBarWhenScrolling = true
        self.navigationItem.searchController = searchController
 


    override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int 

        if (searchController.isActive) 
            return searchArr.count
         else 
             return self.counters
        

    

override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell 

        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: verticalCellId, for: indexPath) as! VerticalCellId
        if (searchController.isActive) 
            cell.titleLabel.text = searchArr[indexPath.row]
            return cell
         else 
            if let link = self.card?[indexPath.item]._imageURL 
                let url = URL(string: link)
                cell.photoImageView.kf.setImage(with: url)
            

            if let title = self.card?[indexPath.item]._title 
                cell.titleLabel.text = title
                titles.append(title)
                print("\(titles)")
            

            if let source = self.card?[indexPath.item]._source 
                cell.sourceLabel.text = source
            

            return cell

        




    

这里是错误定位:

                titles.append(title)
                print("\(titles)")

当我搜索关键字时,过滤结果不正确,因为集合视图单元格会动态变化(我不确定我的表达是否准确)。

但是,如果我像这样设置变量 titles,它会完美运行:

var titles = ["Tom","Jack","Lily"]

但我必须从互联网上检索 titles 的值。任何建议将不胜感激。

下面是self.card之后创建数组的更新问题:

override func viewWillAppear(_ animated: Bool) 
        super.viewWillAppear(true)

        self.view.addSubview(activityView)
        activityView.hidesWhenStopped = true
        activityView.center = self.view.center
        activityView.startAnimating()

        let dynamoDbObjectMapper = AWSDynamoDBObjectMapper.default()
        dynamoDbObjectMapper.load(TheUserIds2018.self, hashKey: "TheUserIds2018", rangeKey: nil, completionHandler:  (objectModel: AWSDynamoDBObjectModel?, error: Error?) -> Void in
            if let error = error 
                print("Amazon DynamoDB Read Error: \(error)")
                return
            

            DispatchQueue.main.async 
                if let count = objectModel?.dictionaryValue["_articleCounters"] 
                    self.counters = count as! Int
                    self.collectionView?.reloadData()
                    self.updateItems()
                    self.activityView.stopAnimating()
                

            

        )

    



 func updateItems() 
        let dynamoDbObjectMapper = AWSDynamoDBObjectMapper.default()
        var tasksList = Array<AWSTask<AnyObject>>()
        for i in 1...self.counters 
            tasksList.append(dynamoDbObjectMapper.load(RecommendArticles.self, hashKey: "userId" + String(self.counters + 1 - i), rangeKey: nil))
        
        AWSTask<AnyObject>.init(forCompletionOfAllTasksWithResults: tasksList).continueWith  (task) -> Any? in
            if let cards = task.result as? [RecommendArticles] 
                self.card = cards
                DispatchQueue.main.async 
                if let totalCounts = self.card?.count 
                    for item in 0...totalCounts - 1 
                        if let title = self.card?[item]._title 
                            self.newTitle = title
                        
                        self.titles.append(self.newTitle)
                        print("titles: \(self.titles)")
                    
                
        


             else if let error = task.error 
                print(error.localizedDescription)
            

            return nil

        

    

【问题讨论】:

【参考方案1】:

这不是 UISearchController 的问题。它与您的数据有关。集合视图数据源方法 -

cellForItemAtIndexPath 仅在单元格出现在视图中时有效。所以你不能在cellForItemAtIndexPath中保留创建标题数组的代码

您可以直接在标题中使用搜索文本过滤self.card数组,而不是单独将标题字符串保存在数组中以供搜索

self.searchArr = self.card?.filter(NSPredicate(format:"_title CONTAINS[cd] %@",searchText)).sorted(byKeyPath: "_title", ascending: true)

您可以在加载集合视图之前创建标题数组 创建self.card之后的一些地方

【讨论】:

谢谢,布里托。但它似乎不起作用,因为 self.card 不是 [String],它是一种 AWSDynamoDBObjectModel、AWSDynamoDBModeling。错误是无法将类型“NSPredicate”的值转换为预期的参数类型“(RecommendArticles) throws -> Bool”。我刚刚编辑了问题。 它不需要是一个字符串。你可以用它的属性过滤任何模型的数组。 您也不能在 cellForItemAtIndexPath 中创建标题字符串数组。答案已更新,请检查 感谢您的所有帮助,布里托。现在它可以使用您建议的第二种方式:在加载集合视图之前创建标题数组 在您创建 self.card 之后的某个位置。我会将答案作为问题的更新。 糟糕,我好像庆祝得太早了。当我在 self.card 之后创建一个标题数组时,每次 viewWillAppear 都会增加标题数组。因为我把 self.card 放在 viewWillAppear 下。因此,在初始 viewWillAppear 之后出现另一个视图时,搜索结果不正确。我把代码放在问题中。你有什么想法可以和我分享吗?谢谢。

以上是关于在 UICollectionViewController (Swift 4) 中实现 UISearchBarController?的主要内容,如果未能解决你的问题,请参考以下文章

NOIP 2015 & SDOI 2016 Round1 & CTSC 2016 & SDOI2016 Round2游记

秋的潇洒在啥?在啥在啥?

上传的数据在云端的怎么查看,保存在啥位置?

在 React 应用程序中在哪里转换数据 - 在 Express 中还是在前端使用 React?

存储在 plist 中的数据在模拟器中有效,但在设备中无效

如何在保存在 Mongoose (ExpressJS) 之前在模型中格式化数据