Статьи

Простое получение основных данных с помощью Magical Record

Magical Record, созданная Saul Mora , представляет собой библиотеку с открытым исходным кодом, которая делает работу с Core Data более простой и элегантной. Библиотека была вдохновлена ​​активной моделью записи, которая также встречается в Ruby on Rails. Этот урок научит вас, как использовать Magical Record в ваших собственных приложениях!

Итак, почему Волшебная Запись ? Если вы разрабатывали для iOS или OS X в течение некоторого времени, скорее всего, у вас был вкус Core Data. Это означает, что вы знаете, что установка стека базовых данных может быть немного громоздкой, и, честно говоря, работа с базовыми данными может быть немного сложной, в основном из-за ее подробного синтаксиса. Например, выборка данных из постоянного хранилища довольно многословна, особенно по сравнению с тем, как приложение Ruby on Rails выполняет эту задачу.


Несмотря на то, что Magical Record действительно облегчает работу с Базовыми данными, важно, чтобы вы хорошо понимали Базовые данные, если решите использовать их в проекте. Несмотря на свое название, Magical Record не выполняет магию за кулисами, которая заставляет Core Data работать по-другому. Другими словами, если вы столкнетесь с проблемами в какой-то момент, очень важно, чтобы вы понимали, как Core Data работает внутренне, чтобы вы могли исправить любые проблемы, которые могут возникнуть по пути.


С момента появления Magical Record требования были увеличены до iOS 5.0 (или выше) или OS X 10.7 (или выше). Также стоит упомянуть, что Magical Record поддерживает ARC из коробки.


Лучший способ показать вам, что может предложить Magical Record — это создать приложение, которое использует эту великолепную библиотеку. Он покажет вам, как легко начать работу с Magical Record, и, начав с нуля, покажет вам, что нужно для создания проекта с Core Data и Magical Record. Приложение, которое мы собираемся создать, представляет собой простое приложение для создания заметок, в котором пользователь может создавать, обновлять и удалять заметки — хороший кандидат на базовые данные.

Поскольку вы читали это далеко, я предполагаю, что вы знакомы с разработкой для iOS и имеете базовые знания о Core Data. В этой статье я сосредоточусь в основном на аспекте Core Data приложения, что означает, что я не буду подробно обсуждать каждый фрагмент кода.


Начните с создания нового проекта на основе шаблона приложения Single View (рисунок 1) и назовите его Magical Notes (рисунок 2). Установите семейство устройств на iPhone и включите ARC, установив флажок « Использовать автоматический подсчет ссылок» . В этом уроке мы не будем использовать раскадровки или юнит-тесты.

Магическая запись и основные данные: настройка проекта - рисунок 1
Магическая запись и основные данные: конфигурация проекта - рисунок 2

Поскольку в этом проекте мы будем использовать Core Data, не забудьте связать ваш проект с платформой Core Data. Поскольку это более продвинутый учебник, я предполагаю, что вы уже знаете, как это сделать.

Добавление библиотеки магических записей в ваш проект не требует никакой магии. Загрузите последнюю версию с GitHub , откройте архив и перетащите папку с именем MagicalRecord в ваш проект Xcode. Не забудьте также скопировать содержимое папки в свой проект, установив флажок « Копировать элементы в папку целевой группы (если необходимо)», и не забудьте добавить библиотеку «Магические записи» к цели «Магические заметки» (рисунок 3). Альтернативный подход к добавлению Magical Record в ваш проект — использование CocoaPods .

Магическая запись и основные данные: добавьте магическую запись - Рисунок 3

Чтобы использовать магическую запись в ваших классах, нам нужно импортировать один заголовочный файл, CoreData+MagicalRecord.h . Однако, поскольку в этом учебном пособии мы будем использовать Magical Record довольно часто, гораздо удобнее вместо этого перенести этот оператор импорта в файл Prefix.pch вашего проекта. Это обеспечит доступность Magical Record в каждом классе вашего проекта.

По умолчанию все методы магической записи имеют префикс MR_ . Вы можете опустить префикс MR_ , добавив одну дополнительную строку в файл Prefix.pch вашего проекта, #define MR_SHORTHAND . Важно, чтобы вы добавили эту строку перед импортом файла заголовка Magical Record.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
//
// Prefix header for all source files of the ‘Magical Notes’ target in the ‘Magical Notes’ project
//
 
#import <Availability.h>
 
#ifndef __IPHONE_4_0
#warning «This project uses features only available in iOS SDK 4.0 and later.»
#endif
 
#ifdef __OBJC__
    #import <UIKit/UIKit.h>
    #import <Foundation/Foundation.h>
 
    #define MR_SHORTHAND
    #import «CoreData+MagicalRecord.h»
#endif

Перед настройкой стека базовых данных нам нужно создать модель базовых данных. Модель базовых данных для этого проекта проста, поскольку она состоит только из одного объекта с именем Note . Сущность Note имеет четыре атрибута: дату , заголовок , текст и ключевые слова . Заголовок, текст и ключевые слова имеют тип string , а date — тип date .

Начните с создания новой модели базовых данных и назовите ее MagicalNotes (рисунок 4). Создайте сущность Note и добавьте четыре атрибута, как указано выше (рисунок 5).

Магическая запись и основные данные: создание базовой модели данных - рисунок 4
Магическая запись и базовые данные: создание базовой модели данных - рисунок 5

Прежде чем двигаться дальше, нам нужно создать собственный подкласс NSManagedObject для сущности Note . Это важно, так как Magical Record добавляет ряд полезных методов класса в класс NSManagedObject , что значительно упростит работу с сущностью Note, как вы увидите через несколько минут. Выберите сущность Note в модели Core Data, создайте новый файл, выберите вкладку Core Data слева и выберите опцию подкласса NSManagedObject справа (рисунок 6).

Магическая запись и основные данные: создание подкласса управляемых объектов - рисунок 6

Настройка базового стека данных довольно трудоемка, если вы не используете один из предоставленных шаблонов XCode. С Magical Record, однако, это не так. application:didFinishLaunchingWithOptions: к application:didFinishLaunchingWithOptions: метод делегата приложения и добавьте следующий фрагмент кода.

1
[MagicalRecord setupCoreDataStack];

Это все, что нужно сделать. По умолчанию название магазина, который создает для вас Magical Record, совпадает с названием вашего приложения. Однако вы можете настроить имя магазина, вызвав вместо него setupCoreDataStackWithStoreNamed: и передав имя магазина.

За кулисами Magical Record создает экземпляр контекста управляемого объекта в основном потоке, а также координатора постоянного хранилища и модели управляемого объекта. Насколько это волшебно?

Ведение журнала . Возможность регистрировать сообщения Core Data и ошибки на консоли встроена в Magical Record. Посмотрите на консоль после первого запуска и запуска приложения. Журналы в консоли показывают, что именно Magical Record делает за кулисами.


Прежде чем мы сможем начать создавать новые заметки, нам нужно немного потрудиться. Пересмотрите приложение вашего Application Delegate application:didFinishLaunchingWithOptions: метод и инициализируйте контроллер навигации с контроллером основного представления в качестве его корневого контроллера представления. Посмотрите на полную реализацию application:didFinishLaunchingWithOptions:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
— (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // Setup Core Data Stack
    [MagicalRecord setupCoreDataStack];
 
    // Initialize View Controller
    self.viewController = [[MTViewController alloc] initWithNibName:@»MTViewController» bundle:nil];
 
    // Initialize Navigation Controller
    UINavigationController *nc = [[UINavigationController alloc] initWithRootViewController:self.viewController];
 
    // Initialize Window
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    [self.window setRootViewController:nc];
    [self.window makeKeyAndVisible];
 
    return YES;
}

Мы будем отображать заметки в табличном представлении, поэтому начнем с добавления выхода для табличного представления в заголовочный файл контроллера основного представления. Выберите файл XIB контроллера основного представления и перетащите экземпляр UITableView в представление контроллера представления. Не забудьте назначить владельца файла в качестве источника данных табличного представления и delegate . Кроме того, обязательно подключите выход представления таблицы «Владелец файла» к представлению таблицы, которое мы только что добавили в его представление.

1
2
3
4
5
6
7
#import <UIKit/UIKit.h>
 
@interface MTViewController : UIViewController
 
@property (nonatomic, weak) IBOutlet UITableView *tableView;
 
@end

В файле реализации контроллера основного представления добавьте частное свойство с именем notes к расширению класса вверху. Убедитесь, что свойство имеет тип NSMutableArray . Свойство notes будет хранить заметки, которые мы извлекаем из хранилища данных, и будет служить источником данных табличного представления.

1
2
3
4
5
6
7
#import «MTViewController.h»
 
@interface MTViewController ()
 
@property (nonatomic, strong) NSMutableArray *notes;
 
@end

В методе viewDidLoad контроллера viewDidLoad мы настраиваем представление, вызывая setupView на главном контроллере представления. Это не что иное, как вспомогательный метод, позволяющий сохранять метод viewDidLoad лаконичным и лаконичным. В setupView мы добавляем кнопку редактирования и добавления на панель навигации и извлекаем заметки из хранилища данных, вызывая метод fetchNotes .

1
2
3
4
5
6
— (void)viewDidLoad {
    [super viewDidLoad];
 
    // Setup View
    [self setupView];
}
01
02
03
04
05
06
07
08
09
10
11
12
— (void)setupView {
    // Create Edit Button
    UIBarButtonItem *editButton = [[UIBarButtonItem alloc] initWithTitle:@»Edit» style:UIBarButtonItemStyleBordered target:self action:@selector(editNotes:)];
    self.navigationItem.leftBarButtonItem = editButton;
 
    // Create Add Button
    UIBarButtonItem *addButton = [[UIBarButtonItem alloc] initWithTitle:@»Add» style:UIBarButtonItemStyleBordered target:self action:@selector(addNote:)];
    self.navigationItem.rightBarButtonItem = addButton;
 
    // Fetch Notes
    [self fetchNotes];
}

Вас может удивить, что метод fetchNotes — это всего лишь одна строка кода. Это все благодаря Magical Record. Извлечение заметок из хранилища данных так же просто, как вызов findAll для класса Note . Метод возвращает массив записей, как и следовало ожидать. Не забудьте импортировать файл заголовка класса Note в верхней части файла реализации контроллера основного представления.

1
2
3
4
— (void)fetchNotes {
    // Fetch Notes
    self.notes = [NSMutableArray arrayWithArray:[Note findAll]];
}

Сортировка записей проста и элегантна. Забудьте дескрипторы сортировки и взгляните на обновленную реализацию метода fetchNotes ниже.

1
2
3
4
— (void)fetchNotes {
    // Fetch Notes
    self.notes = [NSMutableArray arrayWithArray:[Note findAllSortedBy:@»date» ascending:YES]];
}

editNotes: метод прост. Все, что мы делаем, это переключаем стиль редактирования табличного представления. Этого должно быть достаточно на данный момент.

1
2
3
— (void)editNotes:(id)sender {
    [self.tableView setEditing:![self.tableView isEditing] animated:YES];
}

Метод addNote: остается пустым.

1
2
3
— (void)addNote:(id)sender {
 
}

Перед созданием и запуском приложения нам необходимо реализовать необходимые методы протокола источника данных табличного представления. Если вы знакомы с разработкой для iOS, это не должно быть слишком сложно. Взгляните на реализации различных методов ниже для пояснения.

1
2
3
— (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return [self.notes count];
}
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
— (UITableViewCell *)tableView:(UITableView *)aTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *CellIdentifier = @»Cell»;
 
    UITableViewCell *cell = [aTableView dequeueReusableCellWithIdentifier:CellIdentifier];
 
    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
 
        // Configure Cell
        [cell setAccessoryType:UITableViewCellAccessoryDisclosureIndicator];
    }
 
    // Fetch Note
    Note *note = [self.notes objectAtIndex:[indexPath row]];
 
    // Configure Cell
    [cell.textLabel setText:[note title]];
    [cell.detailTextLabel setText:[note keywords]];
 
    return cell;
}
1
2
3
— (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
    return YES;
}
1
2
3
4
5
— (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
    if (editingStyle == UITableViewCellEditingStyleDelete) {
 
    }
}
1
2
3
— (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    [tableView deselectRowAtIndexPath:indexPath animated:YES];
}

Создайте и запустите ваше приложение.


Когда пользователь нажимает кнопку добавления, должен появиться модальный вид, позволяющий пользователю добавить новую заметку в хранилище данных. Создайте новый подкласс UIViewController и назовите его MTEditNoteViewController . Как видно из названия, мы также будем использовать этот контроллер вида для редактирования заметок.

Магическая запись и основные данные: создайте контроллер представления редактирования заметки - рисунок 7

Прежде чем перейти к файлу XIB контроллера представления, добавьте три выхода в файл заголовка контроллера представления. Первые два выхода являются экземплярами UITextField для заголовка и ключевых слов заметки. Третий выход является экземпляром UITextView для тела заметки.

1
2
3
4
5
6
7
8
9
#import <UIKit/UIKit.h>
 
@interface MTEditNoteViewController : UIViewController
 
@property (nonatomic, weak) IBOutlet UITextField *titleField;
@property (nonatomic, weak) IBOutlet UITextField *keywordsField;
@property (nonatomic, weak) IBOutlet UITextView *bodyView;
 
@end

Создание пользовательского интерфейса контроллера представления редактирования заметок не должно быть слишком сложной задачей. Добавьте два экземпляра UITextField и один экземпляр UITextView в представление контроллера представления. Настройте текстовые поля по своему желанию, например, предоставив им текст-заполнитель. Не забудьте соединить выходы владельца файла с текстовыми полями и текстовым представлением.

Магическая запись и основные данные: создание пользовательского интерфейса контроллера представления редактирования заметки - рисунок 8

Поскольку мы будем использовать класс MTEditNoteViewController как для добавления, так и для редактирования заметок, важно, чтобы мы знали, в каком состоянии (добавление или редактирование) находится контроллер представления в любое время. Есть несколько способов решить эту проблему. Одним из способов является добавление частного свойства note в контроллер представления, которое равно nil если создается новая заметка, и устанавливается во время инициализации при редактировании заметки. В подобных ситуациях я предпочитаю работать со специализированными инициализаторами, чтобы избежать путаницы, и это также позволяет мне сохранять свойство note закрытым. В дополнение к свойству private note мы также добавляем второе приватное свойство с именем isEditing , логическое значение. Причина этого станет ясна через несколько минут. Также не забудьте импортировать заголовочный файл класса Note .

01
02
03
04
05
06
07
08
09
10
#import «MTEditNoteViewController.h»
 
#import «Note.h»
 
@interface MTEditNoteViewController ()
 
@property (nonatomic, strong) Note *note;
@property (nonatomic, assign) BOOL isEditing;
 
@end

Давайте рассмотрим различные методы шаг за шагом. Во-первых, мы хотим убедиться, что мы можем добавлять новые заметки в хранилище данных без проблем. Мы начнем с initWithNibName:bundle: метод. Единственное изменение, которое мы вносим, ​​- установка свойства isEditing на NO .

01
02
03
04
05
06
07
08
09
10
— (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
 
    if (self) {
        // Set Flag
        self.isEditing = NO;
    }
 
    return self;
}

Как мы видели ранее, в методе viewDidLoad мы настраиваем представление, вызывая метод setupView в котором мы создаем кнопки отмены и сохранения. Обратите внимание, что мы создаем кнопку отмены только в том случае, если свойство note равно nil . Причина в том, что мы представляем контроллер представления модально при добавлении новых заметок, но мы помещаем контроллер представления в стек навигации при редактировании заметки. Если свойство note не равно nil , мы также заполняем текстовые поля и текстовое представление содержимым свойства note .

1
2
3
4
5
6
— (void)viewDidLoad {
    [super viewDidLoad];
 
    // Setup View
    [self setupView];
}
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
— (void)setupView {
    // Create Cancel Button
    if (!self.note) {
        UIBarButtonItem *cancelButton = [[UIBarButtonItem alloc] initWithTitle:@»Cancel» style:UIBarButtonItemStyleBordered target:self action:@selector(cancel:)];
        self.navigationItem.leftBarButtonItem = cancelButton;
    }
 
    // Create Save Button
    UIBarButtonItem *saveButton = [[UIBarButtonItem alloc] initWithTitle:@»Save» style:UIBarButtonItemStyleBordered target:self action:@selector(save:)];
    self.navigationItem.rightBarButtonItem = saveButton;
 
    if (self.note) {
        // Populate Form Fields
        [self.titleField setText:[self.note title]];
        [self.keywordsField setText:[self.note keywords]];
        [self.bodyView setText:[self.note body]];
    }
}

Метод cancel: не должен содержать сюрпризов.

1
2
3
4
— (void)cancel:(id)sender {
    // Dismiss View Controller
    [self dismissViewControllerAnimated:YES completion:nil];
}

Метод save: немного более многословен, но не должен быть слишком сложным. Сначала мы проверяем, установлено ли свойство note контроллера представления. Если он установлен, то мы знаем, что примечание редактируется, а не создается. Если свойство note равно nil тогда мы знаем, что следует создать новую заметку. Отказ от контроллера представления немного сложен, поскольку нам нужно отклонить контроллер представления, если он представлен модально при создании заметки, и извлечь его из стека навигации при редактировании заметки. По этой причине мы создали свойство isEditing .

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
— (void)save:(id)sender {
    if (!self.note) {
        // Create Note
        self.note = [Note createEntity];
 
        // Configure Note
        [self.note setDate:[NSDate date]];
    }
 
    // Configure Note
    [self.note setTitle:[self.titleField text]];
    [self.note setKeywords:[self.keywordsField text]];
    [self.note setBody:[self.bodyView text]];
 
    // Save Managed Object Context
    [[NSManagedObjectContext defaultContext] saveNestedContexts];
 
    if (self.isEditing) {
        // Pop View Controller from Navigation Stack
        [self.navigationController popViewControllerAnimated:YES];
 
    } else {
        // Dismiss View Controller
        [self dismissViewControllerAnimated:YES completion:nil];
    }
}

Как видите, создание новой заметки — это еще одна строчка при использовании Magical Record. Мы заполняем заметку содержимым полей формы и сохраняем контекст заметки управляемого объекта. Получить ссылку на контекст управляемого объекта легко с помощью Magical Record. Все, что нам нужно сделать, это спросить класс NSManagedObjectContext для контекста по умолчанию. Сохранение контекста идентично сохранению контекста без магической записи. Несмотря на то, что мы регистрируем ошибку, если что-то идет не так, на самом деле в этом нет необходимости, поскольку Magical Record будет регистрировать любые ошибки для нас.

Теперь addNote: время изменить метод addNote: в контроллере основного представления. Не забудьте импортировать файл MTEditNoteViewController класса MTEditNoteViewController .

01
02
03
04
05
06
07
08
09
10
— (void)addNote:(id)sender {
    // Initialize Edit Note View Controller
    MTEditNoteViewController *vc = [[MTEditNoteViewController alloc] initWithNibName:@»MTEditNoteViewController» bundle:[NSBundle mainBundle]];
 
    // Initialize Navigation Controller
    UINavigationController *nc = [[UINavigationController alloc] initWithRootViewController:vc];
 
    // Present View Controller
    [self.navigationController presentViewController:nc animated:YES completion:nil];
}

Всякий раз, когда новая заметка добавляется в хранилище данных, мы должны обновлять табличное представление для отображения изменений. Для производственного приложения лучшим подходом было бы наблюдать изменения в контексте управляемого объекта. Однако в этом примере приложения мы выбираем заметки из хранилища данных и перезагружаем табличное представление каждый раз, когда появляется основное представление (пере). Это дорого и поэтому не рекомендуется, если вы планируете подать заявку в App Store. Для подобных ситуаций идеальным решением является контроллер извлеченных результатов.

1
2
3
4
5
6
7
8
9
— (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
 
    // Fetch Notes
    [self fetchNotes];
 
    // Reload Table View
    [self.tableView reloadData];
}

Обновление заметок почти так же просто, как добавление заметок. Как я упоминал ранее, мы создадим специализированный инициализатор для установки свойства note контроллера представления. Обновите файл MTEditNoteViewController класса MTEditNoteViewController , добавив новый инициализатор, как показано ниже. Не забудьте также добавить в заголовочный файл объявление класса forward для класса Note .

01
02
03
04
05
06
07
08
09
10
11
12
13
#import <UIKit/UIKit.h>
 
@class Note;
 
@interface MTEditNoteViewController : UIViewController
 
@property (nonatomic, weak) IBOutlet UITextField *titleField;
@property (nonatomic, weak) IBOutlet UITextField *keywordsField;
@property (nonatomic, weak) IBOutlet UITextView *bodyView;
 
— (id)initWithNote:(Note *)note;
 
@end

Специализированный инициализатор на самом деле не особенный. Все, что мы делаем, это устанавливаем свойства контроллера представления и свойства isEditing как вы можете видеть ниже.

01
02
03
04
05
06
07
08
09
10
11
12
13
— (id)initWithNote:(Note *)note {
    self = [self initWithNibName:@»MTEditNoteViewController» bundle:[NSBundle mainBundle]];
 
    if (self) {
        // Set Note
        self.note = note;
 
        // Set Flag
        self.isEditing = YES;
    }
 
    return self;
}

Прежде чем мы создадим и запустим приложение еще раз, нам нужно обновить tableView:didSelectRowAtIndexPath: контроллера tableView:didSelectRowAtIndexPath: метод. В этом методе мы выбираем правильную заметку, инициализируем экземпляр класса MTEditNoteViewController и MTEditNoteViewController контроллер представления в стек навигации.

01
02
03
04
05
06
07
08
09
10
11
12
— (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    [tableView deselectRowAtIndexPath:indexPath animated:YES];
 
    // Fetch Note
    Note *note = [self.notes objectAtIndex:[indexPath row]];
 
    // Initialize Edit Note View Controller
    MTEditNoteViewController *vc = [[MTEditNoteViewController alloc] initWithNote:note];
 
    // Push View Controller onto Navigation Stack
    [self.navigationController pushViewController:vc animated:YES];
}

Чтобы удалить заметку, нам нужно изменить tableView:commitEditingStyle:forRowAtIndexPath: метод. Мы извлекаем заметку, удаляем ее из источника данных и контекста управляемого объекта и обновляем представление таблицы. Как видите, удалить запись или объект из хранилища данных так же просто, как отправить ему сообщение deleteEntity .

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
— (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
    if (editingStyle == UITableViewCellEditingStyleDelete) {
        // Fetch Note
        Note *note = [self.notes objectAtIndex:[indexPath row]];
 
        // Delete Note from Data Source
        [self.notes removeObjectAtIndex:[indexPath row]];
 
        // Delete Entity
        [note deleteEntity];
 
        // Update Table View
        [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
    }
}

Создав Магические Записи, мы только поцарапали поверхность. Я хочу подчеркнуть, что Magical Record — это надежная, зрелая библиотека, а не просто объединение нескольких полезных категорий. Как я показал вам, Magical Record делает работу с Core Data намного проще и менее многословной. Общие задачи часто бывают однострочными. Сравните следующие фрагменты кода, чтобы получить все заметки и отсортировать их по дате. Использование Core Data приведет к следующему фрагменту кода.

1
2
3
4
5
6
7
8
9
NSFetchRequest *fr = [[NSFetchRequest alloc] init];
NSEntityDescription *ed = [NSEntityDescription entityForName:@»Note» inManagedObjectContext:[NSManagedObjectContext defaultContext]];
[fr setEntity:ed];
 
NSSortDescriptor *sd = [NSSortDescriptor sortDescriptorWithKey:@»date» ascending:YES];
[fr setSortDescriptors:@[sd]];
 
NSError *error = nil;
NSArray *result = [[NSManagedObjectContext defaultContext] executeFetchRequest:fr error:&error];

Однако при использовании Magical Record для этого требуется только одна строка кода.

1
NSArray *result = [Note findAllSortedBy:@»date» ascending:YES];

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

1
2
3
4
NSPredicate *predicate1 = [NSPredicate predicateWithFormat:@»title contains[cd] %@», query];
NSPredicate *predicate2 = [NSPredicate predicateWithFormat:@»keywords contains[cd] %@», query];
NSPredicate *predicate = [NSCompoundPredicate orPredicateWithSubpredicates:@[predicate1, predicate2]];
NSArray *result = [Note findAllWithPredicate:predicate];

Как я уже сказал, Magical Record может предложить гораздо больше, чем то, что я показал вам в этом уроке. Начиная с версии 2.0, Magical Record может работать с вложенными контекстами, а также обеспечивает поддержку iCloud и многопоточных операций. Основная цель этого урока — показать вам, что Core Data не должен быть громоздким, и Сол Мора иллюстрирует это с помощью Magical Record.