Вступ: Чому Core Data і NSFetchedResultsController Matter

У сучасному iOS розробки, що забезпечує рідину, відчужливий інтерфейс користувача часто залежить від того, наскільки ефективно працює ваш додаток дані, які зміниться за часом. Чи є ви будуєте соціальний корм, менеджер завдань або інвентаризація системи, дані, що відображаються користувачам рідко статичні. Core Data — зрілий граф об'єкта Apple і персистентність — парі з (FRC) пропонує бойово-експедиційний розчин для управління динамічними, масштабними даними, зберігаючи UI в синці без ручного накладу.

Ця стаття надає поглиблений, практичний посібник з використання Core Data з повідомлення є ключовим. Коли об'єкти вставляються, оновлені або видалені, контекст транслює ці зміни, які точно те, що , важелі для збереження вашої UI послідовно.

Для офіційної документації розробника див.

NSFetchedResultsController: Міст між Core Data і ваш UI

- це об'єкт контролера, призначений для ефективного управління результатами, що повернулися з запиту на фейку Core Data, особливо коли основні дані будуть очікувані зміни. Він відстежує відповідний контекст об'єкта та автоматично змінює повідомлення через його делегаційний протокол.

Основні характеристики

  • Автоматичний трек змін: FRC слухає контекстні повідомлення та переводить їх в структуровані делеговані виклики (, , .
  • Built-in розділення: За допомогою параметра , групи контролерів fetch призводить до секцій, що робить його trivial для відображення розділених таблиць або перегляда.
  • Попередня оптимізація: FRC використовує несправність і кешування під капюшоном. Це тільки дані, як необхідні і може додатково використовувати персистентний кеш, щоб уникнути повторного випікання при збереженні керованого контексту об'єкта.

Методи делегування в докладному режимі

Щоб повністю скористатися контролером, необхідно здійснити . Найпоширеніший шаблон полягає в тому, щоб використовувати ці зворотні дзвінки всередині або делегат до пакетного оновлення UI. Наприклад:

func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
 tableView.beginUpdates()
}

func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>,
 didChange anObject: Any,
 at indexPath: IndexPath?,
 for type: NSFetchedResultsChangeType,
 newIndexPath: IndexPath?) {
 switch type {
 case .insert:
 tableView.insertRows(at: [newIndexPath!], with: .fade)
 case .delete:
 tableView.deleteRows(at: [indexPath!], with: .fade)
 case .update:
 tableView.reloadRows(at: [indexPath!], with: .fade)
 case .move:
 tableView.moveRow(at: indexPath!, to: newIndexPath!)
 @unknown default:
 tableView.reloadData()
 }
}

func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
 tableView.endUpdates()
}

Цей шаблон забезпечує, що таблиця переглядає зміни в синхронізації з основними даними, запобігаючи флизелю або невідповідності.

Покрокова реалізація

Нижче наведено повний, виробничо-читацький приклад за допомогою Swift 5, цільового iOS 15+. Ми припустимо, що просту особу, яка називається з атрибутами (String) і (Bool), і (Date).

1. Встановити резервну копію даних Core

або спеціальна (компонент у додатках SwiftUI), створення стійкий контейнер:

class PersistenceController {
 static let shared = PersistenceController()
 let container: NSPersistentContainer

 init() {
 container = NSPersistentContainer(name: "YourModelName")
 container.loadPersistentStores { storeDescription, error in
 if let error = error as NSError? {
 fatalError("Unresolved error \(error), \(error.userInfo)")
 }
 }
 container.viewContext.automaticallyMergesChangesFromParent = true
 }
}

2. Створіть NSManagedObject Subclass

Використовуйте редактор даних Xcode для створення файлів класу або створення їх вручну. Забезпечити вашу особу використовує налаштування модуля правильний клас.

3. Налаштуйте запит Fetch та FRC

У вашому екрані контролер, встановіть запит на фейку і ініціалізуйте контролер fetched результатів. Найкраще це виконувати в або ввімкнути модель перегляду.

lazy var fetchedResultsController: NSFetchedResultsController<Task> = {
 let fetchRequest: NSFetchRequest<Task> = Task.fetchRequest()
 let sortDescriptor = NSSortDescriptor(key: "dueDate", ascending: true)
 fetchRequest.sortDescriptors = [sortDescriptor]
 // Optional: limit results with batch size for large datasets
 fetchRequest.fetchBatchSize = 20

 let controller = NSFetchedResultsController(
 fetchRequest: fetchRequest,
 managedObjectContext: PersistenceController.shared.container.viewContext,
 sectionNameKeyPath: "completionStatus", // e.g., a transient attribute or a computed property
 cacheName: nil
 )
 controller.delegate = self
 try? controller.performFetch()
 return controller
}()

4. Приводіть таблицю Перегляд з FRC

методи стають тривіальними:

func numberOfSections(in tableView: UITableView) -> Int {
 fetchedResultsController.sections?.count ?? 0
}

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
 let sectionInfo = fetchedResultsController.sections![section]
 return sectionInfo.numberOfObjects
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
 let cell = tableView.dequeueReusableCell(withIdentifier: "TaskCell", for: indexPath)
 let task = fetchedResultsController.object(at: indexPath)
 configure(cell, with: task)
 return cell
}

Повідомлення ми ніколи не називаємо вручну — методи делегування ручать кожну вставку, видалення і оновлення.

Розширені практики використання та кращі практики

Безпека нитки

Основні контексти даних не є небезпечними. Завжди використовуйте (який працює на головній черзі) для всіх запитів, пов'язаних з фейками та FRCs. Для фонової роботи, створіть приватний контекст черг та з'єднайте зміни в контекст перегляду. Уникайте використання того ж FRC у декількох чергух.

Панчохи

параметр може поліпшити роботу за допомогою перенапірного розділу та інформації про об'єкт. Однак якщо зміни моделі fetch або даних, ви повинні видалити кеш () для уникнення корупції.

Обробка великих даних

Використовуйте ] для обмеження кількості об'єктів, що задаються в пам'ять. Також розглянути налаштування ] тільки якщо вам потрібен безпосередній доступ до кожного майна. Для зв'язків з даними, попередньо виїмка з може запобігти повторних збоїв.

Інтеграція з SwiftUI

Хоча є UIKit‐centric, ви все ще можете використовувати його в SwiftUI, обгортаючи його в або використовуючи новий об'єкт обгортки (який внутрішньо використовує аналогічний механізм). Для складних динамічних даних в SwiftUI, зазвичай достатній, але FRC дає вам тонкозернований контроль над анімаціями і пакетуванням.

Загальні Питви та Як уникнути

  • Forgetting :] контролер не виконує зчеплення, поки ви не викликав цей метод. Виконайте це один раз, зазвичай прямо після ініціалізації.
  • Не встановивши делегат: Без делегатів зміни не пропагують на вигляд таблиці. Завжди виклику .
  • Інкоректифікаторні дескриптори: Якщо ваш розділ ім'я ключового шляху не відповідає першому дескриптору, з'являються розділи з замовлення. Забезпечити атрибут, який використовується в з'являється в дескрипторах сортування.
  • поряд з FRC: Calling , в той час як FRC є анімація змін може викликати аварійні ситуації. Нехай делеговані методи керують усіма оновленнями UI.
  • Ignoring контексту даних зберігає збої: Якщо ви зберігаєте контекст і виникає помилка, FRC не може бути повідомлено. Завжди ручка помилок і розглянемо використання в фоновому контексті.

Оцінка продуктивності

вже ефективний, але тут є додаткові оптимізацію:

  • Використовувати предикати мудро: Комплексний привід може уповільнити початкову кисть. Використовуйте індексовані атрибути, де можливо.
  • => Якщо вам потрібен лише певні атрибути, встановити на вимогу fetch.
  • Потрібні оновлення: При внесенні багатьох змін, загортання їх в блок для зменшення кількості делегатів зворотнього зв'язку.
  • Задоволення зайвих несправностей: Якщо ви знаєте, що ви отримаєте доступ до всіх об'єктів в результаті, скористайтеся для попереднього запису їх, але обережно з пам'яттю.

Для більш глибокого занурення в продуктивність Core Data див. Керівництво з продуктивності Core Data .

Приклади реального світу

Приклад 1: чат додаток

Додаток обміну повідомленнями відображає список розмов, що відсортовані за останнє повідомлення. Нові вхідні повідомлення повинні з'явитися миттєво. Використання FRC, контактний перегляд може підписатися на зміни тільки для поточних користувачів бесід. Розділення повідомлення про дати в "Сьогодні", "Сьогодні" тощо.

Приклад 2: Управління винахідниками

Додаток електронної комерції показує продукти в категорії. При зміні рівнях запасів з фонової синхронізації, FRC автоматично оновлює UI. Встановивши до 50, вид залишається відповідальним навіть з тисячами одиниць.

Приклад 3: Список To‐Do з категоріями

Класичний приклад: завдання, що загруповані в "Overdue", "Today", "Upcoming". може бути перехідний атрибут, що обчислюється з і дати струму. Забезпечити той же отриманий значення використовується в дескрипторі, щоб уникнути помилок.

Висновок

Магістрування комбінації Core Data та - це кутовий камінь побудови надійних, динамічних додатків iOS. Завантажуючи важке підйому змін відстеження та синхронізації UI до каркасів Apple, ви можете зосередитися на створенні великого досвіду користувача, а не написання кодів обробки даних котелень.

Якщо ви підтримуєте програму Legacy UIKit або приймаєте SwiftUI з , принципи залишаються однаковими: зрозуміти свій граф об'єкта, налаштовувати запити fetch ретельно, і нехай контролер fetched результати робить те, що він робить краще. З практиками, викладеними в цій статті, включаючи кешування, безпеку ниток і продуктивність, що тренується, буде добре обладнаний для обробки будь-яких даних, які перетворюються на час.

Для подальшого розвідки, перевірте Рай Вікліч підручник даних і NSHipster стаття на NSFetchedResultsController.