Ну что ж, начнем!
Сегодня мы посмотрим на работу с двумя NSManageObjectContext и NSFetchedResultsController.
Два NSManageObjectContext и зачем это надо?
Если ваше приложение активно задействует какой-нибудь API через которое оно получает данные, и вы хотите эти данные где-то сохранять, то отличный выбор — Core Data. Какие у вас могут появиться проблемы с этим? Первое и самое очевидное — количество данных будет так велико, что при попытке сохранить их, наше приложение зависнет на какое-то время, что скажется впечатлении пользователя. Обычным GCD тут не обойтись так как независимо, наш Core Data Stack, о котором говорилось тут, работает синхронно и при любом обращении к нашему NSManageObjectContext нам придется ждать до конца выполнения цикла.
Но тут на помощь нам приходит приватный NSManageObjectContext который работает в background потоке. Для того чтобы его вызвать требуется сначала обратиться к нашему NSPersistentContainer.
Инициализация будет выглядеть следующим образом:
lazy var persistentContainer: NSPersistentContainer = { let container = NSPersistentContainer(name: "Preset") container.loadPersistentStores { (persistent, error) in if let error = error { fatalError("Error: " + error.localizedDescription) } } container.viewContext.mergePolicy = NSMergeByPropertyStoreTrumpMergePolicy container.viewContext.shouldDeleteInaccessibleFaults = true container.viewContext.automaticallyMergesChangesFromParent = true return container }()
MergePolicy
Тут вы указываем политику слияния наших NSManageObjectContext. Тут мы явно указываем как должна себя повести Core Data в случае конфликта данных.
Варианты MergePolicy:
- NSRollbackMergePolicy — В случае появления конфликта, отбрасывает все изменения до его появления
- NSOverwriteMergePolicy — Сохранит новые значения независимо от данных
- NSMergeByPropertyStoreTrumpMergePolicy — Сохраняет измененные объекты свойство за свойством, в данном случае преобладать будут сохраненные данные
- NSMergeByPropertyObjectTrumpMergePolicy — Сохраняет измененные объекты свойство за свойством, в данном случае преобладать будут новые данные
AutomaticallyMergesChangesFromParent — говорит о том будет ли наш контекст автоматически объединять данные
После чего создаем новый контекст:
let context = persistentContainer.viewContext let context = persistentContainer.newBackgroundContext()
Теперь у нас имеется два NSManageObjectContext. Первый служит для работы с UI и работает на главном потоке, а второй имеет privateQueueConcurrencyType для работы в фоне.
Мы будем использовать его для скачивания данных.
let object = NSEntityDescription.insertNewObject(forEntityName: "Name", into: context) saveChanges(with: context)
Тут мы создаем наше Entity и далее можем присвоить ему необходимые свойства, после чего вызываем метод сохранения, выглядит он следующим образом:
func saveChanges(with context: NSManagedObjectContext) { context.performAndWait { if context.hasChanges { do { try context.save() } catch { context.rollback() } } context.reset() } }
Есть 2 метода на выбор:
- performAndWait — выполняет действия на потоке контекста синхронно
- perform — выполняет действия на потоке контекста асинхронно
NSFetchedResultsController
NSFetchedResultsController — контроллер который выполняет определенные запросы и показывает необходимые данные пользователю.
lazy var fetchedResultsController: NSFetchedResultsController<Pack> = { let fetchRequest = NSFetchRequest<Pack>(entityName:"Pack") fetchRequest.fetchBatchSize = 20 fetchRequest.sortDescriptors = [NSSortDescriptor(key: "name", ascending:true)] let controller = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: context, sectionNameKeyPath: nil, cacheName: nil) controller.delegate = self do { try controller.performFetch() } catch { print(error.localizedDescription) } return controller }()
NSFetchedResultsController имеет очень большое количество конфигураций, разберем парочку из них:
На данный момент мы имеем NSFetchedResultsController который должен отобразить наши данные в таблице. Для того чтобы обновить данные нужно вызвать метод делегата:
extension ViewController: NSFetchedResultsControllerDelegate { func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) { collectionView.reloadData() } }
Данный метод делегата срабатывает когда у нас происходят какие-то изменения в нашем контексте. В данной реализации это происходит после того как мы сохраняем данные в privateContext. В этот момент у нас срабатывает метод делегата и данные обновляются.
Всего пару действий и Core Data из обычной базы данных превращается в мощное оружие любого IOS разработчика.
Happy Coding!
ссылка на оригинал статьи https://habr.com/ru/post/495602/
Добавить комментарий