Civil &: строительная инженерия
Использование базовых данных с Nsfetchedresultscontroller для динамических данных в Ios
Table of Contents
Введение: Почему важны основные данные и результаты NSFetched
В современной разработке iOS, доставка гибкого, отзывчивого пользовательского интерфейса часто зависит от того, насколько эффективно ваше приложение обрабатывает данные, которые меняются с течением времени. Независимо от того, создаете ли вы социальную ленту, диспетчер задач или систему инвентаризации, данные, отображаемые пользователям, редко статичны. Core Data — зрелый объектный граф Apple и структура устойчивости — в сочетании с FLT:0 (FRC) предлагает проверенное на практике решение для управления динамическими, крупномасштабными наборами данных при сохранении синхронизации пользовательского интерфейса без ручных накладных расходов.
Эта статья содержит подробное практическое руководство по использованию основных данных с уведомлениями . Когда объекты вставляются, обновляются или удаляются, контекст транслирует эти изменения, что именно и позволяет поддерживать согласованность пользовательского интерфейса.
Для официальной документации разработчика обратитесь к ссылке на Core Data Framework Reference .
Контроллер результатов NSFetched: мост между основными данными и вашим пользовательским интерфейсом
является объектом контроллера, предназначенным для эффективного управления результатами, возвращаемыми из запроса на получение основных данных, особенно когда ожидается изменение базовых данных. Он контролирует соответствующий контекст управляемых объектов и автоматически сообщает об изменениях через свой протокол делегата.
Ключевые особенности
- Автоматическое отслеживание изменений: FRC слушает контекстные уведомления и переводит их в структурированные обратные вызовы делегатов , , .
- Бойл-в разделе: Указывая на , группы контроллеров получают результаты в разделах, что делает тривиальным отображение разрезанных представлений таблиц или просмотров коллекций.
- Оптимизация производительности: FRC использует неисправности и кэширование под капотом. Он только извлекает данные по мере необходимости и может необязательно использовать постоянный кэш, чтобы избежать повторной привязки, когда контекст управляемого объекта сохраняется.
Делегатские методы в деталях
Чтобы полностью воспользоваться контроллером, вы должны реализовать . Наиболее распространенным шаблоном является использование этих обратных вызовов внутри или делегировать пакетное обновление пользовательского интерфейса.
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.Настройка основного стека данных
В ваших или выделенных (обычные в приложениях 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
Используйте редактор модели данных Xcode для генерации файлов класса или создания их вручную. Убедитесь, что ваша организация использует правильную настройку модуля класса.
3. Настройка запроса Fetch и FRC
В контроллере просмотра настройте запрос на получение и инициализируйте контроллер полученных результатов. Лучше всего выполнить это в или в init модели просмотра.
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. Drive the Table View with the FRC (Вид на стол)
Ваши методы [[ФЛТ:21]] становятся тривиальными:
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 в нескольких очередях.
кеширование
Параметр может улучшить производительность запуска, сохраняя информацию о разделе и объекте. Однако, если ваш запрос на получение или модель данных изменится, вы должны удалить кэш (]), чтобы избежать коррупции.
Обработка больших наборов данных
Используйте , чтобы ограничить количество объектов, вносимых в память. Также рассмотрите возможность установки только в том случае, если вам нужен немедленный доступ к каждому свойству. Для данных, требующих отношений, предварительная выборка с может предотвратить повторные ошибки.
Интеграция с SwiftUI
Хотя FLT:30 является UIKit-центричным, вы все еще можете использовать его в SwiftUI, обернув его в или используя более новую обертку свойств (которая внутренне использует аналогичный механизм). Для сложных динамических данных в SwiftUI, обычно достаточно, но FRC дает вам мелкозернистый контроль над анимацией и пакетированием.
Обычные подводные камни и как их избежать
- Забывание : Контроллер не будет выполнять выборку, пока вы не вызовете этот метод. Сделайте это один раз, обычно сразу после инициализации.
- Не устанавливая делегата: Без делегата изменения не будут распространяться на вид таблицы. Всегда звоните.
- Неправильные дескрипторы сортировки: Если ваш путь с именем раздела не соответствует дескриптору первого сорта, разделы могут появляться не в порядке.
- Использование наряду с FRC: Звонок в то время как FRC анимирует изменения, может вызвать сбои.
- Игнорирование контекста данных с сохранением сбоев: Если вы сохраняете контекст и происходит ошибка, FRC может не быть уведомлен. Всегда обрабатывайте ошибки и рассмотрите возможность использования в фоновых контекстах.
Соображения в отношении эффективности
уже эффективен, но вот дополнительные оптимизации:
- Используйте предикаты с умом: Сложный предикат может замедлить начальный вывод. Используйте индексированные атрибуты, где это возможно.
- Ограничить приносимые свойства: Если вам нужны только определенные атрибуты, установите на запрос привносимости.
- Обновления для матчей: При внесении многих изменений оберните их в блок , чтобы уменьшить количество возвратов делегатов.
- Избегать ненужных ошибок: Если вы знаете, что вы получите доступ ко всем объектам в наборе результатов, используйте , чтобы предварительно их получить, но будьте осторожны с памятью.
Для более глубокого погружения в производительность основных данных см. Руководство по производительности основных данных Apple .
Реальные примеры
Пример 1: Чат-приложение
Приложение для обмена сообщениями отображает список разговоров, отсортированных по последнему сообщению. Новые входящие сообщения должны появляться мгновенно. Используя FRC, вид контакта может подписываться на изменения только для субъектов разговора текущего пользователя. Разделение по группам дат сообщений на «Сегодня», «Вчера» и т. д.
Пример 2: Управление запасами
Приложение электронной коммерции показывает продукты в категориях. Когда уровни акций меняются от фоновой синхронизации, FRC автоматически обновляет пользовательский интерфейс. Установив до 50, вид остается отзывчивым даже с тысячами предметов.
Пример 3: Список дел с категориями
Классический пример: задачи, сгруппированные в «Overdue», «Today» и «Upcoming»., могут быть переходным производным атрибутом, вычисленным из и текущей даты. Убедитесь, что то же производное значение используется в дескрипторе сортировки, чтобы избежать несоответствий.
Заключение
Освоение комбинации основных данных и является краеугольным камнем создания надежных, динамических приложений iOS. Путем загрузки тяжелого снятия отслеживания изменений и синхронизации пользовательского интерфейса в фреймворки Apple вы можете сосредоточиться на создании отличного пользовательского опыта, а не на написании кода управления данными.
Независимо от того, поддерживаете ли вы устаревшее приложение UIKit или используете SwiftUI с , принципы остаются прежними: поймите график объекта, тщательно настройте запросы на получение и позвольте контроллеру полученных результатов делать то, что он делает лучше всего. С помощью методов, изложенных в этой статье, включая кэширование, безопасность потоков и настройку производительности, вы будете хорошо оснащены для обработки любого набора данных, который развивается с течением времени.
Для дальнейшего изучения ознакомьтесь с учебником по основным данным Рэя Вендерлиха и статьей NSFetchedResultsController .