使用Swift CoreData进行动态过滤

时间:2018-10-02 15:27:44

标签: ios swift core-data filter

我正在开发一个从CoreData检索数据的应用程序。我从数据库中检索出一个项目列表,并将它们显示在屏幕上。

用户可以选择在5个单独的下拉菜单中为多达5个类别过滤这些项目。动态执行此操作的最佳方法是什么?我的意思是,如果用户选择一个过滤器选项,则仅显示与该过滤器匹配的项目,以及其他过滤器选项,然后仅显示已经过滤的项目存在的过滤器选项。

我希望这是有道理的!

这是我目前用于检索项目的代码:

func showDropDown(filterButton: UIButton) -> Void {
        selectedButton = filterButton
        let popController = UIStoryboard(name: STORYBOARD_NAME,
                                         bundle: nil).instantiateViewController(withIdentifier: STORYBOARD_ID) as! FilterDropDownViewController

        popController.modalPresentationStyle = .popover
        popController.delegate = self
        popController.popoverPresentationController?.permittedArrowDirections = .up
        popController.popoverPresentationController?.delegate = self
        popController.popoverPresentationController?.sourceView = filterButton
        popController.popoverPresentationController?.sourceRect = filterButton.bounds

        let appDelegate = UIApplication.shared.delegate as! AppDelegate
        let context = appDelegate.persistentContainer.viewContext

        let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "Item")
        var predicate = NSPredicate(format: "code matches[c] '\(code!)'")
        fetchRequest.returnsObjectsAsFaults = false
        fetchRequest.predicate = predicate
        let entity = NSEntityDescription.entity(forEntityName: "Item",
                                                in: context)

        fetchRequest.resultType = .dictionaryResultType
        let entityProperties = entity?.propertiesByName
        let filterToFetch = "filter\(filterButton.tag)"
        let propertiesToFetch: [Any] = [entityProperties![filterToFetch]!]
        fetchRequest.propertiesToFetch = propertiesToFetch
        fetchRequest.returnsDistinctResults = true

        var result = [[String : String]]()

        do {
            result = try context.fetch(fetchRequest) as! [[String : String]]
        } catch {
            print("Unable to fetch managed objects for Item).")
        }

        var filterArray = [Filter]()
        for dict in result {
            if let search = dict[filterToFetch] {
                predicate = NSPredicate(format: "code matches[c] '\(search)'")
                let filterCode = DatabaseHelper.fetchRecordsForEntity(entity: "Filter",
                                                                      managedObjectContext: context,
                                                                      predicate: predicate) as! [Filter]

                filterArray.append(filterCode.first!)
            }
        }

        popController.filterArray = filterArray

        present(popController, animated: true, completion: nil)
}

1 个答案:

答案 0 :(得分:1)

您可以通过以下简单步骤进行操作:

  1. 根据当前过滤器设置(使用NSFetchResultsController),使用适当的谓词创建一个NSCompoundPredicate,然后进行提取。将视图控制器设置为委托,并在数据更改时重新加载collectionView的数据(似乎您不希望用户在查看数据时更改数据,因此可以保持简单)。更新NSFetchResultsController时,请不要忘记重新加载collectionView。
  2. 现在遍历NSFetchResultsController中的所有fetchedObjects,并查看它具有哪些可过滤的属性。将这些属性添加到一组(每个过滤器类别一个)。然后查看集合以确定要显示和更新UI的过滤器。
  3. 当过滤器更改时,将当前NSFetchResultsController的委托设置为nil,然后再创建新的代理,并按照步骤1中的说明创建新的代理。

在您共享的代码中,您无需进行复杂的提取就可以确定哪些过滤器是相关的。我不知道您的代码是否正确,但是我知道它很复杂。而且,只需在fetchResultsController中查看您已经可以访问的managedObject中的属性,速度就会更快。这些项目已经被获取并存储在内存中,因此不需要再次访问数据库。与用代码过滤这些项目相比,弄清楚如何编写一个复杂的谓词要容易得多。