Я хочу универсальный fetchedResultController для CoreData для поддержки нескольких моделей - PullRequest
0 голосов
/ 22 ноября 2018

Я упростил свою задачу, чтобы упростить вопрос, поэтому, надеюсь, кода, который я публикую, достаточно.

Моя цель - использовать один класс, который может поддерживать несколько моделей из CoreData, чтобы избежать повторного созданияодин и тот же материал для каждого класса.

class FRC<T> where T: NSManagedObject {
    let context: NSManagedObjectContext

    fileprivate lazy var fetchedResultscontroller: NSFetchedResultsController<T> = { [weak self] in
        guard let this = self else {
            fatalError("lazy property has been called after object has been descructed")
        }
        guard let request = T.fetchRequest() as? NSFetchRequest<T> else {
            fatalError("Can't set up NSFetchRequest")
        }
        request.sortDescriptors = [NSSortDescriptor(key: "key", ascending: true)]
        return NSFetchedResultsController<T>(fetchRequest: request,
                                             managedObjectContext: this.context,
                                             sectionNameKeyPath: nil,
                                             cacheName: nil)
        }()

    init(context: NSManagedObjectContext) {
        self.context = context
    }
}

enum ModelType {
    case modelA
    case modelB
}

class GenericDataModel: NSObject {
    let container: NSPersistentContainer
    // STUPID!!!
    var frcA: FRC<ModelA>?
    var frcB: FRC<ModelB>?

    init(modelType: ModelType) {
        container = NSPersistentContainer(name: "MyContainer")
        container.loadPersistentStores { _, error in /* Handle */ }
        // Below here is ugly!
        switch modelType {
        case .modelA:
            frcA = FRC<ModelA>(context: container.viewContext)
        case .modelB:
            frcB = FRC<ModelB>(context: container.viewContext)
        }
    }
}

extension GenericDataModel: NSFetchedResultsControllerDelegate {
    func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>,
                    didChange anObject: Any,
                    at indexPath: IndexPath?,
                    for type: NSFetchedResultsChangeType,
                    newIndexPath: IndexPath?) {
        // Handle
    }
}

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

Однако попытка создать единственную локальную переменную для класса FRC не удалась, и я не могу понять, почему.

Я новичок в дженериках, поэтому, скорее всего, я просто делаю глупости.

1 Ответ

0 голосов
/ 22 ноября 2018

Это неплохая идея.Я уже сделал это: https://github.com/jon513/FetchedResultsControllerNeverCrash/blob/master/coreDataNeverCrash/FetchedResultsControllerManager.swift

В нем реализован метод, при котором данные ядра никогда не будут падать при одновременном получении удаления и обновления (см. Приложение аварийно завершает работу после обновления модели CoreData, отображаемой вUITableView ), а также немного упрощает API.

Чтобы использовать его, создайте FetchedResultsControllerManager с fetchRequest, context и делегатом.

Реализация делегата проста:

extension ViewController : FetchedResultsControllerManagerDelegate {
    func managerDidChangeContent(_ controller: NSObject, change: FetchedResultsControllerManagerChange) {
        change.applyChanges(collectionView: collectionView)
    }
}

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...