NSFetchedResultsController и поиск — возвращают несколько и отдельные разделы?

#swift #core-data #nsfetchedresultscontroller #uisearchcontroller

#swift #core-data #nsfetchedresultscontroller #uisearchcontroller

Вопрос:

Редактировать:

Поблагодарите pbasdf за помощь в решении этой проблемы.

Исправлен код:

    lazy var fetchedResultsController = self.getFetchedResultsController()
    var sectionKeyPath: String? = #keyPath(Object.sectionKey)
    var searchPredicate: NSCompoundPredicate?
   
    // MARK: - Return FRC:
    private func getFetchedResultsController() -> NSFetchedResultsController<Object> { // var fetchedResultsController:
        print("Lazy: getFetchedResultsController()")
        let fetchRequest: NSFetchRequest<Object> = Object.fetchRequest()
        fetchRequest.predicate = searchPredicate
        
        let sortByKey = NSSortDescriptor(key: #keyPath(Object.sectionKey), ascending: true)
        let sortByName = NSSortDescriptor(key: #keyPath(Object.name), ascending: true)
        
        fetchRequest.sortDescriptors = [sortByKey, sortByName]
        fetchRequest.fetchBatchSize = 20
        
        let fetchedResultsController = NSFetchedResultsController(
            fetchRequest: fetchRequest,
            managedObjectContext: coreDataStack.managedContext,
            sectionNameKeyPath: sectionKeyPath ?? nil,
            cacheName: nil)
        
        fetchedResultsController.delegate = self
        return fetchedResultsController
    }
    
    private func refreshFRC() {
        fetchedResultsController = getFetchedResultsController() // Reset FRC
        do {  // Load Data:
            try fetchedResultsController.performFetch()
        } catch let error as NSError {
            print("Fetching error: (error), (error.userInfo)")
        }
    }
  

Это дает вам FRC с необязательным предикатом и sectionNameKeyPath. Которые затем вы можете настроить в соответствии с вашими потребностями, а затем установить изменения с помощью refreshFRC().


Я работаю над добавлением поиска в tableview с использованием NSFetchedResultsController. Моя цель:

  • Возвращает несколько разделов на основе первой буквы объекта
  • Возвращайте все объекты в один раздел при поиске.

У меня есть рабочий код. И я могу заставить таблицу выполнять оба в зависимости от моего sectionKey, я просто не могу понять, как сделать оба в одной сборке.

Это нормальное поведение, и я пытаюсь сделать что-то невозможное, изменив FRC sectionNameKeyPath и sortDescriptors? Или я просто что-то упускаю?

 private func getFetchedResultsController() -> NSFetchedResultsController<Object> {
        let fetchRequest: NSFetchRequest<Object> = Object.fetchRequest()
        
        let sortByKey = NSSortDescriptor(key: #keyPath(Object.sectionKey), ascending: true)
        let sortByName = NSSortDescriptor(key: #keyPath(Object.name), ascending: true)
        
        switch sectionKeyPath {
        case nil:
            fetchRequest.sortDescriptors = nil
            fetchRequest.fetchBatchSize = 20
        default:
            fetchRequest.sortDescriptors = [sortByKey, sortByName]
            fetchRequest.fetchBatchSize = 20
        }
        fetchRequest.sortDescriptors = [sortByKey, sortByName]
        fetchRequest.fetchBatchSize = 20
        
        let fetchedResultsController = NSFetchedResultsController(
            fetchRequest: fetchRequest,
            managedObjectContext: coreDataStack.managedContext,
            sectionNameKeyPath: sectionKeyPath ?? nil,
            cacheName: nil)
        fetchedResultsController.delegate = self
        return fetchedResultsController
    }
  

Мне также интересно, лучше ли использовать один FRC для всего ViewController, или было бы лучшим подходом создать один для всего списка объектов, а второй только для того, когда поиск активен?


 func updateSearchResults(for searchController: UISearchController) {
    let searchBar = searchController.searchBar
    searchBar.barStyle = .default
    
    switch searchBar.text?.count {
    case nil:
        searchPredicate = nil
        sectionKeyPath = #keyPath(Object.sectionKey)
        tableView.reloadData()
    case 0:
        searchPredicate = nil
        sectionKeyPath = #keyPath(Object.sectionKey)
        tableView.reloadData()
    default:
        sectionKeyPath = nil
        guard let searchText = searchBar.text else { return }
        setSearchPredicate(search: searchText)
    }
    fetchFRC()
    tableView.reloadData()
} // End: updateSearchResults()

func fetchFRC() {
    do {
        try fetchedResultsController.performFetch()
    } catch let error as NSError {
        print("Fetching error: (error), (error.userInfo)")
    }
}
  

Комментарии:

1. Можете ли вы прояснить проблему? Вы, кажется, говорите, что можете заставить его работать, но затем говорите, что не можете.

2. Привет. Мои извинения. — Я пытаюсь заставить FRC возвращать один раздел, когда пользователь использует панель поиска, и несколько разделов на основе первой буквы объекта в одной сборке. — Я могу выполнить оба по отдельности, в зависимости от того, использую ли я sectionNameKeyPath . — Я попытался привязать sectionNameKeyPath к переменной, которая изменяется при активном поиске, но при поиске все равно возвращается несколько разделов. — Поиск также полностью функционален. — Моя проблема заключается в попытке выяснить, как вернуть несколько разделов при отсутствии поиска и один раздел при поиске.

3. Можете ли вы показать код, который переключается между «обычным» (многосекционным) режимом и режимом «поиска»? Предположительно, вы меняете sectionKeyPath, а затем повторно вызываете getFetchedResultsController код в своем вопросе?

4. Я думаю, вам нужно повторно вызвать getFetchedResultsController перед fetchFRC в этом updateSearchResults коде.

5. У вас должен быть FRC в качестве переменной в вашем контроллере представления: вам нужно присвоить результат getFetchedResultsController вызова этой переменной.

Ответ №1:

Согласно комментариям:

  1. Вам нужно повторно вызвать getFetchedResultsController перед fetchFRC в этом updateSearchResults коде; и
  2. Вам нужно присвоить результат fetchedResultsController переменной, определенной в вашем контроллере представления.