Я загружаю информацию из Интернета и используя данные для создания объектов в Core Data. Я пытаюсь сортировать объекты (сущности - это ТВ-шоу, данные из Trakt) атрибутом airDate
объекта TVEpisode
, который имеет отношение к объекту TVShow
. Объект TVShow
имеет это отношение только к показу, если у показанных данных есть эпизод, который будет транслироваться в будущую дату с текущего времени.Вставка строк с несколькими NSFetchedResultsController
Так как я хочу, чтобы отсортировать данные в: Top: Показывает, имеющие отношение upcomingEpisode, отсортированный по атрибуту upcomingEpisode
airDate
, упорядоченный по возрастанию. Середина: Показывает, что у них нет отношений upcomingEpisode
, но будет возвращаться. Дно: показывает, что у них нет отношений upcomingEpisode
, и которые завершены/отменены
Вот проблемы, с которыми я столкнулся, чтобы заставить это работать.
Выпуск 1: Использование 1 NSFetchedResultsController
let fetchRequest = NSFetchRequest(entityName: "TVShow")
let airDateSort = NSSortDescriptor(key: "upcomingEpisode.airDate", ascending: true)
let titleSort = NSSortDescriptor(key: "title", ascending: true)
fetchRequest.sortDescriptors = [airDateSort, titleSort];
upcomingShowsResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: coreDataStack.context, sectionNameKeyPath: nil, cacheName: "upcomingShows")
upcomingShowsResultsController.delegate = self;
var error: NSError? = nil
if (!upcomingShowsResultsController.performFetch(&error)) {
println("Error: \(error?.localizedDescription)")
}
Используя этот NSFetchedResultsController
приложу все TVShow
сущности, не upcomingEpisode
отношений на вершине, отсортированные все по названию, мне нужны мертвые шоу, отсортированные по названию на самом дне и возвращающие шоу сортируются по названию в середине.
Выпуск 2: Использование нескольких NSFetchedResultsController
«ы
func setupUpcomingShowsFetchedResultsController() {
let fetchRequest = NSFetchRequest(entityName: "TVShow")
let airDateSort = NSSortDescriptor(key: "upcomingEpisode.airDate", ascending: true)
let titleSort = NSSortDescriptor(key: "title", ascending: true)
fetchRequest.sortDescriptors = [airDateSort, titleSort];
let predicate = NSPredicate(format: "upcomingEpisode != nil")
fetchRequest.predicate = predicate
upcomingShowsResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: coreDataStack.context, sectionNameKeyPath: nil, cacheName: "upcomingShows")
upcomingShowsResultsController.delegate = self;
var error: NSError? = nil
if (!upcomingShowsResultsController.performFetch(&error)) {
println("Error: \(error?.localizedDescription)")
}
}
func setupReturningShowsFetchedResultsController() {
let fetchRequest = NSFetchRequest(entityName: "TVShow")
let titleSort = NSSortDescriptor(key: "title", ascending: true)
fetchRequest.sortDescriptors = [titleSort];
let predicate = NSPredicate(format: "status == 'returning series'")
let predicate2 = NSPredicate(format: "upcomingEpisode == nil")
fetchRequest.predicate = NSCompoundPredicate.andPredicateWithSubpredicates([predicate!, predicate2!])
returningShowsResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: coreDataStack.context, sectionNameKeyPath: nil, cacheName: nil)
returningShowsResultsController.delegate = self;
var error: NSError? = nil
if (!returningShowsResultsController.performFetch(&error)) {
println("Error: \(error?.localizedDescription)")
}
}
func setupDeadShowsFetchedResultsController() {
let fetchRequest = NSFetchRequest(entityName: "TVShow")
let titleSort = NSSortDescriptor(key: "title", ascending: true)
fetchRequest.sortDescriptors = [titleSort]
let endedShowsPredicate = NSPredicate(format: "status == 'ended'")
fetchRequest.predicate = endedShowsPredicate
deadShowsResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: coreDataStack.context, sectionNameKeyPath: nil, cacheName: nil)
deadShowsResultsController.delegate = self;
var deadShowsError: NSError? = nil
if (!deadShowsResultsController.performFetch(&deadShowsError)) {
println("Error: \(deadShowsError?.localizedDescription)")
}
}
Они работают для того, что я хочу, но только тогда, когда данные уже загружены и в Core Data. Когда приложение сначала запускает и загружает данные, они сбрасываются каждый раз, потому что количество строк в разделе не совпадает с тем, что ожидает таблица. Я манипулировал указательными путями, которые дает NSFetchedResultsControllerDelegate
в функции didChangeObject
, и я распечатал индекс, который вставляется. Счет, который я делал в любом разделе, был равен тому, сколько табличного представления говорит, что он ожидал, но каждый раз он выдает ошибку. Это, как я обработка метод многократного NSFetchedResultsController's
func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?) {
let section = sectionOfFetchedResultsController(controller)
let indexPathsComputed = [NSIndexPath(forRow: indexPath?.row ?? 0, inSection: section)]
let newIndexPathsComputed = [NSIndexPath(forRow: newIndexPath?.row ?? 0, inSection: section)]
dispatch_async(dispatch_get_main_queue(), {() -> Void in
switch type {
case NSFetchedResultsChangeType.Insert:
self.tableView.insertRowsAtIndexPaths(newIndexPathsComputed, withRowAnimation: .Automatic)
case NSFetchedResultsChangeType.Delete:
self.tableView.deleteRowsAtIndexPaths(indexPathsComputed, withRowAnimation: .Automatic)
case NSFetchedResultsChangeType.Move:
self.tableView.deleteRowsAtIndexPaths(indexPathsComputed, withRowAnimation: .Automatic)
self.tableView.insertRowsAtIndexPaths(newIndexPathsComputed, withRowAnimation: .Automatic)
case NSFetchedResultsChangeType.Update:
if let index = indexPathsComputed[0] {
if let cell = self.tableView.cellForRowAtIndexPath(index) as? ShowTableViewCell {
self.configureCell(cell, indexPath: index)
}
}
else {
println("No cell at index path")
}
}
})
}
Если сбой может быть исправлен, это будет лучшим способом добиться того, что я хочу сделать.
Выпуск 3: Использование множественного массива
func reloadShowsArray() {
let fetchRequest = NSFetchRequest(entityName: "TVShow")
let airDateSort = NSSortDescriptor(key: "upcomingEpisode.airDate", ascending: true)
let titleSort = NSSortDescriptor(key: "title", ascending: true)
fetchRequest.sortDescriptors = [airDateSort, titleSort];
let predicate = NSPredicate(format: "upcomingEpisode != nil")
fetchRequest.predicate = predicate
var error: NSError?
showsArray = coreDataStack.context.executeFetchRequest(fetchRequest, error: &error) as [TVShow]
if let error = error {
println(error)
}
}
func reloadDeadShows() {
let fetchRequest = NSFetchRequest(entityName: "TVShow")
let titleSort = NSSortDescriptor(key: "title", ascending: true)
fetchRequest.sortDescriptors = [titleSort]
let endedShowsPredicate = NSPredicate(format: "status == 'ended'")
fetchRequest.predicate = endedShowsPredicate
var error: NSError?
deadShows = coreDataStack.context.executeFetchRequest(fetchRequest, error: &error) as [TVShow]
if let error = error {
println(error)
}
}
Это решает Сбои и работает после того, как данные загружены, и в то время как данные загружаются. Но при использовании этого я должен позвонить self.tableView.reloadData()
, когда данные будут загружены, а сущности просто появятся в представлении таблицы без анимации, и я действительно хочу анимацию от insertRowsAtIndexPaths
, потому что она выглядит лучше и лучше. Я попробовал позвонить reloadShowsArray()
, а затем использовать функцию find()
с сущностью, чтобы получить индекс, чтобы я мог использовать insertRowsAtIndexPaths, но каждый раз для индекса он возвращает nil, даже если объект был сохранен с контекстом до этого. Кроме того, ячейки не будут автоматически перезагружаться или перемещаться, как с помощью NSFetchedResultsController
Итак, каков наилучший способ справиться с этим, и как я могу получить нужную сортировку с помощью анимаций?
Для варианта 1, что является «статусом» шоу в верхней части? Не могли бы вы сначала отсортировать «статус», чтобы получить верхний/средний/нижний в правильном порядке? Для варианта 2 у вас есть tableView.beginUpdates() и tableView.endUpdates() в других методах делегата FRC? Если нет, это может объяснить ошибки. И даже в этом случае вам может потребоваться реализовать счетчик, который увеличивается с каждым вызовом 'controller: willChangeContent' и уменьшается с каждым вызовом' controller: didChangeContent'. beginUpdates следует вызывать только в том случае, если счетчик равен нулю, и endUpdates только тогда, когда он возвращается к нулю. – pbasdf
Также в варианте 2 ошибки могут быть связаны с dispatch_async, так как это может привести к обновлению таблицы вне цикла beginUpdates/endUpdates. – pbasdf
Статус «возвращение серии» для лучших шоу, «в производстве» для средних шоу и «закончился»/«отменен» для нижних показов. Я не знаю, почему, но сортировка по тому, что раньше не работала так, как я хотел. Я могу попробовать еще раз, но у него была странная сортировка. Я также попробую счетчик, который может работать. Я использую dispatch_async там, потому что я думал, что это будет проще, чем сохранить контекст в каждом месте основного потока, потому что в сетевых запросах они не находятся на главном нить, поэтому просто убедитесь, что они вставлены правильно. – Maximilian