В этой серии мы создали приложение под названием Orny . Приложение будет (гипотетически) использоваться орнитологами для записи наблюдений за птицами, где происходили эти наблюдения, и, возможно, даже будет хранить фотографии, сделанные пользователем.
На данный момент мы перечисляем несколько видов птиц в массиве. В ближайшем будущем мы хотим сохранить данные, поэтому мы заставим наше приложение использовать CoreData. В этом уроке мы расскажем об основах CoreData, о том, как создать базу данных по умолчанию и как извлечь из нее информацию. В следующей статье мы обсудим, как хранить данные наблюдений в базе данных, что приблизит нас к созданию полезного приложения.
Создание схемы
Первое, что мы собираемся сделать, — это создать схему для нашего приложения. Если вы работали с базами данных раньше, это должно быть достаточно знакомым.
Схема — это совокупность «сущностей» (часто называемых «таблицами» в мире веб-разработки). Каждый объект имеет атрибуты, которые его описывают, и может иметь отношения с другими объектами. Например, сущность «стул» может иметь четыре связанных сущности, называемых «ножками». Вы можете получить доступ к определенным chair.legs
сущности кафедры, используя метод доступа, например, так: chair.legs
(который предположительно вернет массив).
Мы пока не будем вдаваться в мелочность отношений сущностей, но они не очень сложны.
Когда мы впервые создали наш проект, мы сказали XCode, что хотим использовать управляемые сущности CoreData, поэтому у нас уже есть модель данных.
Нажмите Orny.xcdatamodeld
(это файл определения модели данных).
Вы должны увидеть один из следующих двух экранов:
Вы можете переключаться между ними, используя «Стиль редактора» в правом нижнем углу.
Чтобы добавить объект, нажмите кнопку «Добавить объект».
Рисунок 4
Эта кнопка иногда может быть помечена как «Добавить запрос на выборку» или «Добавить конфигурацию» в зависимости от того, что вы добавили ранее — в этом случае, сделайте длинный щелчок по кнопке, и вы увидите опцию «Добавить объект»
Создайте сущность с именем Species.
Нажмите кнопку «+» в разделе «Атрибуты», чтобы добавить некоторые атрибуты — имя, имя файла и текстовое описание.
Нам нужно указать типы этих атрибутов — все они должны быть строками. Рядом с каждым атрибутом выберите раскрывающийся список для типа и измените их соответствующим образом.
Добавление классов управляемых моделей
Теперь мы создали нашу схему, но нам нужно создать в коде представления сущностей, которыми мы управляем. iOS называет эти «Модели» (как в «Модель, Вид, Контроллер»). Мы запрашиваем подмножества данных в базе данных, используя запросы выборки, которые будут возвращать массивы моделей. Каждый экземпляр класса модели представляет строку в базе данных (или, по крайней мере, делает это после того, как мы сохранили ее в базе данных).
Модели, которые CoreData предоставляет нам, обычно являются «управляемыми» — если мы внесем в них изменения, а затем скажем соответствующему контроллеру постоянного хранилища выполнить «сохранение», он сохранит все изменения, которые мы внесли в любой из наших экземпляров модели. (По сути, это шаблон Active Record , который имеет свои сильные и слабые стороны, но довольно хорошо понят.)
Если у вас его еще нет, создайте папку «Модели» в своем проекте (щелкните правой кнопкой мыши «Orny» в файловом браузере и выберите «Новая группа».)
Щелкните правой кнопкой мыши новую группу моделей и выберите «Новый файл».
Выберите «Основные данные» и «Подкласс NSManagedObject».
Рисунок 8
Нажмите «Далее» и выберите модель данных «Орни».
Нажмите «Далее», выберите «Виды»
Назовите файл Species, и все готово. Это создает класс модели — Species.m
, заголовок которого выглядит следующим образом:
@interface Species : NSManagedObject { @private } @property (nonatomic, retain) NSString * name; @property (nonatomic, retain) NSString * text_description; @property (nonatomic, retain) NSString * filename; @end
Вы можете предоставить свои собственные методы получения и установки, если хотите, для применения бизнес-логики в вашей модели. Обычно лучше поместить большую часть своей логики в модели и оставить контроллеры как можно более «тонкими», но это очень простой класс, который мы пока не собираемся изменять.
Запрос и получение результатов
Наш appDelegate уже имеет большинство методов, которые нам нужны для доступа к нашей базе данных. Взгляните на OrnyAppDelegate.m
и, в частности, методы managedObjectContext
, managedObjectModel
, persistentStoreCoordinator
и saveContext
.
persistentStoreCoordinator
создает экземпляр нашей базы данных из файла .sqlite и соотносит содержимое этого файла с нашей моделью управляемых объектов с помощью managedObjectModel
. Мы изменим это позже, чтобы скопировать в нашу базу данных, если ни один не существует при запуске (см. Ниже).
managedObjectContext
получает контекст управляемого объекта (что удивительно удивительно!), который является корреляцией файла базы данных, модели управляемого объекта и контроллера, который используется для получения результатов и сохранения данных. NSManagedObjectContext
— это класс, с которым мы будем взаимодействовать больше всего.
Наши цели здесь — хранить данные о видах птиц в базе данных и отображать эти данные пользователю. Отображение данных происходит в нашем BirdListViewController
, поэтому давайте изменим метод loadData
следующим образом:
-(void)loadBirdData { // The context is, roughly, the "database schema" NSManagedObjectContext *context = [(OrnyAppDelegate*)[[UIApplication sharedApplication] delegate] managedObjectContext]; // A request is like an SQL select statement; we're retrieving some set of objects NSFetchRequest *request = [[NSFetchRequest alloc] init]; // An entity description is used to specify which entit(y|ies) we want to pull from the context NSEntityDescription *description = [NSEntityDescription entityForName:@"Species" inManagedObjectContext:context]; [request setEntity:description]; // A sort descriptor lets us order the results NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"name" ascending:NO]; [request setSortDescriptors:[NSArray arrayWithObject:sortDescriptor]]; // A fetchedResultsController handles the fetching of our data NSFetchedResultsController *fetchController = [[NSFetchedResultsController alloc] initWithFetchRequest:request managedObjectContext:context sectionNameKeyPath:nil cacheName:nil]; fetchController.delegate = self; NSError *error = nil; if(![fetchController performFetch:&error]) { // TODO: Handle error abort(); } birds = fetchController.fetchedObjects; }
Здесь происходит немало, но комментарии должны объяснить это немного. По сути, мы запрашиваем группу объектов из базы данных, где ранее мы создавали NSMutableArray для хранения этой информации.
Ooh. Мы изменили формат наших структур данных. Ранее мы вызывали [birds objectAtIndex:someIndex]
чтобы получить определенную «строку» в нашем наборе данных. Затем мы вызываем [species objectForKey:@"name"]
или тому подобное, чтобы получить атрибут этого вида.
Нам нужно переписать еще немного нашего BirdListViewController
, в частности tableView:tableView cellForRowAtIndexPath:indexPath
: