2016-01-28 6 views
2

У меня есть объекты с собственностью NSDate, и мне нужно разбить их на два раздела (события первого - будущего, события второго - исторического), а затем для первого раздела мне нужно отсортировать их по дате свойство в порядке возрастания, а вторая - в порядке убывания. Любая идея, как сделать сортировку?NSFetchedResultsController различные дескрипторы сортировки для каждого раздела

ответ

-1

Сначала установите свои сортировки дескрипторы в fetchRequest

func itemFetchRequest() -> NSFetchRequest{ 

    let fetchRequest = NSFetchRequest(entityName: "Events") 
    let primarySortDescription = NSSortDescriptor(key: "futureEvents", ascending: true) 
    let secondarySortDescription = NSSortDescriptor(key: "historicEvents", ascending: false) 
    fetchRequest.sortDescriptors = [primarySortDescription, secondarySortDescription] 
    return fetchRequest 
} 

затем установите количество секций

func numberOfSectionsInTableView(tableView: UITableView) -> Int { 
    let numberOfSections = frc.sections?.count 
    return numberOfSections! 
} 

и, наконец, ваши заголовки разделов

func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String?{ 
    let sectionHeader = Future Events 
    let sectionHeader1 = Historic Events 
     if (section== "0") { 
      return sectionHeader 
     } else { 
      return sectionHeader1 
     } 
    } else { 
     return nil 
    } 
} 
+0

Какие futureEvents и ключи historicEvents? Объект Event имеет только одно свойство - date: NSDate –

+0

Извините, я предположил, что у вас есть атрибут для двух, потому что вы хотели, чтобы они были заголовками разделов. Возможно, вам придется отделить их, если хотите, чтобы они были на отдельных разделах. –

2

Предполагая, что вы используете NSFetchedResultsController , базовая выборка должна быть отсортирована так или иначе. Я могу думать о двух разных решениях:

  1. Используйте два отдельных FRCS, с дополнительными предикатами, так что один обрабатывает события прошлого, в то время как другие обрабатывают будущие события. Один будет отсортирован по возрастанию, другой - по убыванию. Проблема состоит в том, что оба FRC будут генерировать indexPaths для раздела 0. Поэтому вам необходимо переназначить второй код FRC indexPaths, чтобы использовать раздел 1 таблицыView. Например, в cellForRowAtIndexPath вам нужно будет что-то вроде этого:

    if (indexPath.section == 0) { 
        objectToDisplay = self.futureFetchedResultsController.objectAtIndexPath(indexPath) 
    } else { // use second FRC 
        let frcIndexPath = NSIndexPath(forRow: indexPath.row, inSection: 0) 
        objectToDisplay = self.pastFetchedResultsController.objectAtIndexPath(frcIndexPath) 
    } 
    
  2. В качестве альтернативы, придерживаться одной FRC, сортируются по возрастанию. Тогда переназначить indexPath для второй секции, так что последний объект в разделе отображается в строке 0, и т.д.:

    if (indexPath.section == 0) { 
        objectToDisplay = self.fetchedResultsController.objectAtIndexPath(indexPath) 
    } else { // use remap to reverse sort order FRC 
        let sectionInfo = self.fetchedResultsController.sections[1] as! NSFetchedResultsSectionInfo 
        let sectionCount = sectionInfo.numberOfObjects 
        let frcIndexPath = NSIndexPath(forRow: (sectionCount - 1 - indexPath.row), inSection:indexPath.section) 
        objectToDisplay = self.fetchedResultsController.objectAtIndexPath(frcIndexPath) 
    } 
    

Лично я считаю, что второй вариант является предпочтительным. В каждом случае всем методам datasource/delegate tableView будет нужно одно и то же переназначение, и для методов делегатов FRC потребуется обратное сопоставление.

0

Чтобы решить общую проблему - желая различного упорядочения для каждого раздела, вы можете обернуть несколько объектов NSFetchedResultsController в один объект, который выравнивает массивы секций в один массив и переназначает результаты таких функций, как func object(at: IndexPath), а также указателей в уведомлениях NSFetchedResultsControllerDelegate.

Это позволит вам решить общую проблему, требующую отображения любого количества разделов, упорядоченных по-разному.

я был пойти на создание этого объекта обертку, и это, кажется, работает хорошо:

/** 
A CompoundFetchedResultsController is a wrapper of a number of inner NSFetchedResultsControllers. 
The wrapper flattens the sections produced by the inner controllers, behaving as if all sections 
were fetched by a single controller. Additionally, change notifications are mapped before being 
passed to the optional NSFetchedResultsControllerDelegate property, so that the section indices 
in the notifications reflect the flattened section indicies. 

Example use case: a table where sections should be ordered in mutually opposing ways. E.g., if 
section 1 should be ordered by propery A ascending, but section 2 should be ordered by property A 
descending. In this case, two controllers can be created - one ordering ascending, the other de- 
scending - and wrapped in a CompoundFetchedResultsController. This will maintain the ease of use 
in a UITableViewController, and the functionality provided by a NSFetchedResultsControllerDelegate. 
*/ 
class CompoundFetchedResultsController<T: NSFetchRequestResult>: NSObject, NSFetchedResultsControllerDelegate { 

    // The wrapperd controllers 
    let controllers: [NSFetchedResultsController<T>] 

    // A delegate to notify of changes. Each of the controllers' delegates are set to this class, 
    // so that we can map the index paths in the notifications before forwarding to this delegate. 
    var delegate: NSFetchedResultsControllerDelegate? { 
     didSet { controllers.forEach{$0.delegate = self} } 
    } 

    init(controllers: NSFetchedResultsController<T>...) { self.controllers = controllers } 

    func performFetch() throws { controllers.forEach{try? $0.performFetch()} } 

    var sections: [NSFetchedResultsSectionInfo]? { 
     // To get the flattened sections array, we simply reduce-by-concatenation the inner controllers' sections arrays. 
     get { return controllers.flatMap{$0.sections}.reduce([], +) } 
    } 

    func object(at indexPath: IndexPath) -> T { 
     // Use the flattened sections array to get the object at the (flattened) index path 
     return sections![indexPath.section].objects![indexPath.row] as! T 
    } 

    func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) { 
     // Forward on the willChange notification 
     delegate?.controllerWillChangeContent?(controller) 
    } 

    func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) { 
     // Forward on the didChange notification 
     delegate?.controllerDidChangeContent?(controller) 
    } 

    private func sectionOffset(forController controller: NSFetchedResultsController<NSFetchRequestResult>) -> Int { 
     // Determine the index of the specified controller 
     let controllerIndex = controllers.index(of: controller as! NSFetchedResultsController<T>)! 

     // Count the number of sections present in all controllers up to (but not including) the supplied controller 
     return controllers.prefix(upTo: controllerIndex).map{$0.sections!.count}.reduce(0, +) 
    } 

    func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) { 

     let sectionOffset = self.sectionOffset(forController: controller) 

     // Index Paths should be adjusted by adding to the section offset to the section index 
     func adjustIndexPath(_ indexPath: IndexPath?) -> IndexPath? { 
      guard let indexPath = indexPath else { return nil } 
      return IndexPath(row: indexPath.row, section: indexPath.section + sectionOffset)  
     } 

     // Forward on the notification with the adjusted index paths 
     delegate?.controller?(controller, didChange: anObject, at: adjustIndexPath(indexPath), for: type, newIndexPath: adjustIndexPath(newIndexPath)) 
    } 

    func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange sectionInfo: NSFetchedResultsSectionInfo, atSectionIndex sectionIndex: Int, for type: NSFetchedResultsChangeType) { 

     let sectionOffset = self.sectionOffset(forController: controller) 

     // Forward on the notification with the adjusted section index 
     delegate?.controller?(controller, didChange: sectionInfo, atSectionIndex: sectionIndex + sectionOffset, for: type) 
    } 
} 
Смежные вопросы