RestKit — это мощная библиотека, которая упрощает взаимодействие с веб-сервисами для приложений iOS. В этой статье, написанной создателем RestKit и техническим директором Two Toasters Блейком Уоттерсом, мы кратко рассмотрим набор функций RestKit, познакомимся с основными концепциями, представленными библиотекой, а затем исследуем некоторые примеры кода, чтобы понять, что работает с RestKit действительно нравится.
Что такое RestKit?
RestKit — это платформа Objective-C для iOS, цель которой — сделать взаимодействие с веб-сервисами RESTful простым, быстрым и увлекательным. Он сочетает в себе чистый, простой HTTP-запрос / ответ API с мощной системой отображения объектов, которая сокращает объем кода, который вам нужно написать, чтобы «выполнить работу». Основная цель RestKit — позволить разработчику больше думать о модели данных своего приложения и меньше беспокоиться о деталях отправки запросов, разборе ответов и построении представлений удаленных ресурсов.
Что предоставляет RestKit?
- Простая высокоуровневая система запросов / ответов HTTP. RestKit поставляется с HTTP-клиентом, созданным поверх NSURLConnection, и предоставляет библиотеку полезных методов для проверки типов MIME и кодов состояния. Подача данных формы так же проста, как предоставление словаря параметров, а собственный объект params включен для легкого создания составных представлений. Также предоставляется простая поддержка потоковой загрузки больших файлов (например, видео).
- Поддержка на уровне инфраструктуры для переключения серверов и сред (например, разработка, производство, подготовка). RestKit использует базовые URL-адреса и пути к ресурсам, а не полные URL-адреса, чтобы вы могли быстро переключать целевые серверы. Интерполяция строк URL и построение объектов NSURL остались в прошлом.
- Система отображения объектов. RestKit предоставляет уровень моделирования для декларативного отображения полезных нагрузок обработанных данных в нативные объекты Какао. Это позволяет программисту приложения перестать беспокоиться о разборе и просто попросить инфраструктуру асинхронно извлечь удаленный ресурс и вызвать делегата с результатами. Сопоставление объектов реализовано с использованием кодирования ключ-значение, что позволяет быстро проходить анализируемый граф объекта. Отражение используется в типах свойств, чтобы разрешить сопоставление из значений, которые не имеют прямых представлений в формате кодирования, таких как сопоставление меток времени JSON, закодированных в виде строки, объектам NSDate.
- Поддержка основных данных. Построенный поверх слоя отображения объектов, RestKit обеспечивает интеграцию с платформой Apple Core Data. Эта поддержка позволяет RestKit сохранять удаленно загруженные объекты непосредственно обратно в локальное хранилище либо в виде быстрого локального кэша, либо в качестве основного хранилища данных, которое периодически синхронизируется с облаком. RestKit может заполнить ассоциации Core Data для вас, позволяя естественное свойство на основе обхода вашей модели данных. Он также предоставляет хороший API поверх примитивов Core Data, который упрощает настройку и запрос вариантов использования.
- Заполнение базы данных. Когда используется хранилище объектов Core Data, вы можете заполнить базу данных из коллекции файлов данных. Это позволяет вам отправлять свои приложения в App Store с базой данных в комплекте приложений, которая готова к немедленному использованию.
- Съемный слой разбора. RestKit в настоящее время поддерживает JSON через парсеры SBJSON и YAJL. Синтаксический анализ реализован за простым интерфейсом, что позволяет прозрачно обрабатывать дополнительные форматы данных.
- Rails интеграция. RestKit изначально был задуман как ответ Objective-C на Active Resource. Rails использовался в качестве бэкэнда для ряда iOS-приложений с поддержкой RestKit, и для взаимодействия с бэкэнд-приложением Rails предоставляется поддержка «под ключ».
- Экспериментальная интеграция Three20. RestKit часто используется вместе с платформой Three20. В дистрибутив включен дополнительный модуль, который позволяет RestKit взаимодействовать с Three20 по протоколу TTModel.
Встать и бежать
RestKit доступен в виде загружаемого бинарного пакета, в виде версионного снимка или в виде подмодуля Git, если вы хотите отслеживать разработку основной линии. Для пользователей библиотеки, не заинтересованных в разработке, мы рекомендуем использовать бинарные пакеты с версиями для простоты установки. Если вы хотите установить как субмодуль или собрать библиотеку самостоятельно, обратитесь к документации, доступной на Github.
Вы можете установить RestKit в несколько простых шагов:
- Перейдите на restkit.org и загрузите последнюю версию (v0.9.0 на момент написания статьи).
- Распакуйте архив туда, где вы хотите хранить библиотеки (автор рекомендует подкаталог Library).
- Перетащите файл RestKit.xcodeproj в файл проекта Xcode. Он будет добавлен в раздел « Группы и файлы » на левой панели проекта. Выберите подходящие цели и нажмите «Добавить», когда появится лист.
- Нажмите на запись для RestKit.xcodeproj в разделе групп и файлов вашего проекта. В правой панели найдите записи для libRestKitSupport.a , libRestKitObjectMapping.a , libRestKitNetwork.a и libRestKitJSONParserYAJL.a и установите флажки в правом нижнем углу под серебряным целевым значком. Это свяжет ваш проект с RestKit. Если вы хотите использовать поддержку Core Data, установите флажок рядом с libRestKitCoreData.a . Ваш проект должен выглядеть примерно так:
- Найдите цель для вашего приложения в разделе Targets вашего проекта. Щелкните правой кнопкой мыши на цели вашего приложения и выберите «Get Info» в меню, чтобы открыть окно инспектора информации о цели.
- Вы должны смотреть на вкладку Общие инспектора вашей цели. В верхнем разделе « Прямые зависимости » нажмите кнопку «плюс» и добавьте прямую зависимость от цели RestKit.
- Теперь посмотрите на нижнюю часть панели « Общие», которая называется « Связанные библиотеки» . Нажмите кнопку «плюс», чтобы открыть лист выбора Frameworks. Найдите и выберите следующие рамки и нажмите «Добавить»:
- CFNetwork.framework — Требуется для поддержки сети.
- SystemConfiguration.framework — требуется для обнаружения доступности сети.
- MobileCoreServices.framework — Обязательно. Обеспечивает поддержку автоматического определения типа MIME для загружаемых файлов.
- CoreData.framework — обязательно. Требуется для использования хранилища постоянных объектов с базовыми данными.
- Перейдите на вкладку «Сборка» в инспекторе проектов. Убедитесь, что во всплывающем меню « Конфигурация» указано « Все конфигурации», чтобы ваши изменения работали для всех конфигураций сборки.
- Найдите настройку Пути поиска заголовка . Дважды щелкните и добавьте новую запись. Когда RestKit скомпилирован, он скопирует все соответствующие заголовки в соответствующее расположение в каталоге / Build в проверке RestKit. Вам необходимо добавить путь к каталогу / Build RestKit относительно файла вашего проекта. Например, если вы вынули субмодуль в подкаталог «Библиотеки» вашего проекта, путь к заголовку будет «Библиотеки / RestKit / Build».
Теперь найдите параметр « Другие флаги компоновщика» . Дважды щелкните по нему и добавьте записи для -all_load и -ObjC . Ваши настройки должны соответствовать скриншоту ниже.
-
Закройте окно инспектора.
Поздравляем, вы закончили добавлять RestKit в свой проект!
Теперь вам нужно только добавить включения для библиотек RestKit в соответствующих местах в вашем приложении. Соответствующие включают в себя:
1
2
3
|
#import <RestKit/RestKit.h>
#import <RestKit/CoreData/CoreData.h>
// If you are using Core Data…
|
Создайте проект, чтобы убедиться, что все работает правильно.
После того, как вы убедились, что RestKit правильно связан с вашим проектом, вы готовы начать использовать библиотеку.
Использование RestKit
RestKit разработан, чтобы сделать общие задачи максимально простыми и простыми. В этом разделе мы рассмотрим много общих задач в библиотеке и сосредоточимся на примерах кода, которые помогут вам начать работу с библиотекой.
Отправка запросов и обработка ответов
Вся функциональность более высокого уровня RestKit построена поверх сетевого уровня. Основная ответственность сетевого уровня заключается в создании и отправке запросов и обработке ответов. Обычно вы отправляете все запросы через класс RKClient.
RKClient — это объект веб-клиента, настроенный для взаимодействия с конкретным веб-сервером. Он инициализируется с помощью базового URL-адреса и позволяет вам настроить конфигурацию, которая является общей для запросов в вашем приложении, таких как заголовки HTTP и информация для аутентификации. Хотя вы можете инициализировать столько экземпляров RKClient, сколько подходит для вашего приложения, существует общий одноэлементный экземпляр, который доступен по всему миру. Этот одноэлементный экземпляр часто настраивается в applicationDidFinishLaunching:withOptions:
делегата вашего приложения applicationDidFinishLaunching:withOptions:
method:
1
2
3
|
— (void)applicationDidFinishLaunching:(UIApplication*)application withOptions:(NSDictionary*)options {
RKClient* client = [RKClient clientWithBaseURL:@»http://restkit.org»];
}
|
Первый инициализированный RKClient автоматически настраивается как одноэлементный экземпляр и становится доступным с помощью одноэлементного метода sharedClient:
1
|
NSLog(@»I am your RKClient singleton : %@», [RKClient sharedClient]);
|
Теперь, когда у вас настроен клиент, вы можете отправлять и обрабатывать HTTP-запросы через клиента. RestKit делает это очень легким для вас и отвлекает от вас детали низкого уровня NSURLConnection. Делая запрос через клиента, вы указываете путь к ресурсу на удаленном веб-сервере, с которым хотите взаимодействовать. Поскольку наиболее распространенным действием в приложении iOS является выполнение асинхронного запроса к удаленному веб-сервису, RestKit предоставляет очень простые удобные методы для глаголов HTTP: GET, POST, PUT и DELETE. Вам нужно только объявить, что ваш класс реализует протокол RKRequestDelegate, а затем предоставить реализацию request:didLoadResponse:
метод. Давайте посмотрим на пример класса, который показывает основы:
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
|
#import <RestKit/RestKit.h>
// Here we declare that we implement the RKRequestDelegate protocol
// Check out RestKit/Network/RKRequest.h for additional delegate methods
// that are available.
@interface RKRequestExamples : NSObject <RKRequestDelegate> {
}
@end
@implementation RKRequestExamples
— (void)sendRequests {
// Perform a simple HTTP GET and call me back with the results
[[RKClient sharedClient] get:@»/foo.xml» delegate:self];
// Send a POST to a remote resource.
// converted into a URL encoded representation and sent along as the request body
NSDictionary* params = [NSDictionary dictionaryWithObject:@»RestKit» forKey:@»Sender»];
[[RKClient sharedClient] post:@»/other.json» params:params delegate:self];
// DELETE a remote resource from the server
[[RKClient client] delete:@»/missing_resource.txt» delegate:self];
}
— (void)request:(RKRequest*)request didLoadResponse:(RKResponse*)response {
if ([request isGET]) {
// Handling GET /foo.xml
if ([response isOK]) {
// Success!
NSLog(@»Retrieved XML: %@», [response bodyAsString]);
}
} else if ([request isPOST]) {
// Handling POST /other.json
if ([response isJSON]) {
NSLog(@»Got a JSON response back from our POST!»);
}
} else if ([request isDELETE]) {
// Handling DELETE /missing_resource.txt
if ([response isNotFound]) {
NSLog(@»The resource path ‘%@’ was not found.», [request resourcePath]);
}
}
}
@end
|
Как видите, код чрезвычайно лаконичен и читабелен. Существует несколько вспомогательных методов, доступных в RKRequest и RKResponse, которые упрощают проверку состояния вашего запроса. Обязательно прочитайте заголовки и ознакомьтесь с тем, что доступно.
Введение в сопоставление объектов
Отправка и получение HTTP-запросов с такой легкостью — это прекрасно, но это только верхушка айсберга. Истинная мощь RestKit исходит не от сетевого уровня, а от уровня отображения объектов, который расположен поверх него. Сопоставление объектов — это решение RestKit для упрощения и СУЩЕСТВОВАНИЯ чрезмерно подробного рабочего процесса:
- Отправка запроса на удаленный веб-сервис.
- Возвращение ответа XML или JSON и его анализ.
- Взятие проанализированного ответа и присвоение значений внутри полезной нагрузки для объектов.
Поскольку RKClient — это ваш путь к более простой жизни с HTTP, RKObjectManager — это ваш путь в мир отображения объектов. Фактически, в проектах, где широко используется сопоставление объектов, вы инициализируете RKObjectManager вместо RKClient. Поскольку RKClient стремится абстрагироваться от мельчайших деталей обработки запросов, RKObjectManager усердно работает, чтобы оградить вас от сложностей преобразования полезных данных в объекты.
Моделирование и загрузка удаленных объектов
Для отображения объектов требуется предоставить класс модели данных для представления удаленных объектов. Реализуя протокол RKObjectMappable, вы настраиваете RestKit для сопоставления атрибутов в извлеченной полезной нагрузке со свойствами в классе вашей модели. Ключом к этому процессу является метод elementToPropertyMappings
, который определяет словарь ключевых путей и имен свойств. Ключевые пути — это строки, соответствующие кодированию значения ключа для доступа к данным в разобранном документе. Имя свойства — это просто строковое имя свойства класса, которому назначаются доступные данные.
Чтобы проиллюстрировать эти моменты, давайте представим, что наше приложение имеет упрощенную концепцию контактов, содержащую имя, адрес электронной почты и идентификационный номер. Давайте представим, что эта запись находится на нашем удаленном сервере в /contacts/1234
. JSON выглядит так:
1
2
3
|
{‘id’: 1234,
‘name’: ‘Blake Watters’,
‘company’: ‘Two Toasters’}
|
Давайте соберем класс RKObject для хранения этих данных:
01
02
03
04
05
06
07
08
09
10
11
|
@interface Contact : RKObject {
NSNumber* _identifier;
NSString* _name;
NSString* _company;
}
@property (nonatomic, retain) NSNumber* identifier;
@property (nonatomic, retain) NSString* name;
@property (nonatomic, retain) NSString* company;
@end
|
Теперь нам нужно просто сказать RestKit, как сопоставить данные из полезной нагрузки с нашими свойствами:
01
02
03
04
05
06
07
08
09
10
11
|
@implementation Contact
— (NSDictionary*)elementToPropertyMappings {
return [NSDictionary dictionaryWithKeysAndObjects:
@»id», @»identifier»,
@»name», @»name»,
@»company», @»company»,
nil];
}
@end
|
Теперь все готово для загрузки данных. Для этого мы устанавливаем RKObjectManager и выполняем GET для записи. RKObjectManager создаст и настроит для вас асинхронный запрос RKObjectLoader и отправит его на удаленный сервер для обработки. Вместо реализации низкоуровневых методов RKRequestDelegate, которые обрабатывают запросы и ответы, мы вместо этого реализуем протокол RKObjectLoaderDelegate и получим обратный вызов с набором сопоставленных объектов или с ошибкой. Давайте посмотрим на этот код:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
|
— (void)loadContact {
RKObjectManager* manager = [RKObjectManager objectManagerWithBaseURL:@»http://restkit.org»];
[manager loadObjectsAtResourcePath:@»/contacts/1″ objectClass:[Contact class] delegate:self]
}
// RKObjectLoaderDelegate methods
— (void)objectLoader:(RKObjectLoader*)objectLoader didLoadObjects:(NSArray*)objects {
Contact* contact = [objects objectAtIndex:0];
NSLog(@»Loaded Contact ID #%@ -> Name: %@, Company: %@», contact.id, contact.name, contact.company);
}
— (void)objectLoader:(RKObjectLoader*)objectLoader didFailWithError:(NSError*)error {
NSLog(@»Encountered an error: %@», error);
}
|
Как видите, весь процесс очень церемонный и абсолютно СУХОЙ.
Настройка маршрутов
Загрузка объектов — это только половина истории. Чтобы по-настоящему взаимодействовать с удаленным веб-сервисом, вам также необходимо иметь возможность создавать, обновлять и удалять экземпляры удаленных объектов. Смешивающим фактором в этих взаимодействиях часто является то, что путь к ресурсу, на котором находится объект, специфичен для каждого экземпляра. Возвращаясь к приведенному выше примеру контактов, представьте, что весь мир контактов представлен следующими парами глаголов HTTP и путей к ресурсам:
-
GET /contacts
возвращает все контакты в виде коллекции -
POST /contacts
создает новый контакт -
GET /contacts/<id>
возвращает конкретные контактные данные -
PUT /contacts/<id>
обновляет существующие контактные данные -
DELETE /contacts/<id>
удаляет существующий контакт
Чтобы избежать засорения кода этими соглашениями и путями к ресурсам, RestKit предлагает систему маршрутизации, способную генерировать пути к ресурсам для объекта. Маршрутизация разработана как расширяемая система для обеспечения гибкости, но RestKit поставляется с очень способной реализацией в классе RKDynamicRouter. Маршрутизация включается путем назначения экземпляра объекта, реализующего протокол RKRouter, RKObjectManager и соответствующей настройки маршрутизатора. Давайте рассмотрим пример конфигурации с использованием RKDynamicRouter и наш контактный пример:
1
2
3
4
5
6
7
|
RKDynamicRouter* router = [RKDynamicRouter new];
// Define a default resource path for all unspecified HTTP verbs
[router routeClass:[Contact class] toResourcePath:@»/contacts/(identifier)»];
[router routeClass:[Contact class] toResourcePath:@»/contacts» forMethod:RKRequestMethodPOST];
[RKObjectManager sharedManager].router = router;
|
Примечательной частью конфигурации является использование круглых скобок в пути к ресурсу для маршрута по умолчанию. В скобках вы можете указать любой метод экземпляра для настраиваемого класса, и когда RestKit генерирует путь ресурса для этого объекта, возвращаемое значение будет интерполировано в строку.
В нашем примере выше мы видим, что операции GET, PUT и DELETE будут генерировать / contacts / 1234, а POST — / contacts.
Управление удаленными объектами
Теперь, когда мы настроили маршрутизацию, мы можем манипулировать представлениями удаленных объектов на очень высоком уровне. Давайте посмотрим на еще немного кода, а затем пройдемся по процессу:
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)createObject {
Contact* joeBlow = [Contact object];
joeBlow.name = @»Joe Blow»;
joeBlow.company = @»Two Toasters»;
// POST to /contacts
[[RKObjectManager sharedManager] postObject:joeBlow delegate:self];
}
— (void)updateObject {
Contact* blake = [Contact object];
blake.identifier = [NSNumber numberWithInt:1];
blake.name = @»Blake Watters»;
blake.company = @»RestKit»;
// PUT to /contacts/1
[[RKObjectManager sharedManager] putObject:blake delegate:self];
}
— (void)deleteObject {
Contact* blake = [Contact object];
blake.identififer = [NSNumber numberWithInt:1];
// DELETE to /contacts/1
[[RKObjectManager sharedManager] deleteObject:blake delegate:self];
}
|
Здесь мы использовали объединенную мощь сопоставления объектов и маршрутизации для выполнения манипуляций очень высокого уровня с локальными и удаленными объектами. За кулисами RestKit определил соответствующий путь ресурса для вашей операции, создал и отправил асинхронный запрос и обработал ответ для вас.
Обзор ключевых концепций
-
Клиент и менеджер объектов. В вашем приложении есть две основные точки входа для работы с RestKit: RKClient и RKObjectManager. RKClient является основной точкой входа, когда вы работаете с сетевым уровнем RestKit и занимается низкоуровневыми деталями построения и отправки запросов. RKObjectManager работает на более высоком уровне абстракции в слое Object Mapping и занимается загрузкой и манипулированием объектами, представляющими удаленные ресурсы. В зависимости от того, что вы пытаетесь достичь с помощью RestKit, вы будете интенсивно работать с одним (или обоими!) Из этих классов.
-
Базовые URL и пути к ресурсам. RestKit использует понятия «Базовый URL» и «Путь к ресурсу» для координации доступа к представлениям удаленных объектов. Базовый URL-адрес является просто общей частью всех URL-адресов вашего удаленного приложения и используется для инициализации экземпляров классов RKClient и RKObjectManager. Путь к ресурсу — это просто часть пути (или подпути) полного URL-адреса к HTTP-ресурсу. Учитывая объект RKClient, инициализированный с « http://restkit.org » и запрос на получение содержимого по пути к ресурсу «/foo/bar.json», RestKit создаст и отправит запрос на « http://restkit.org». /foo/bar.json ‘ . Это позволяет вам легко поддерживать среды разработки, подготовки и производства в ваших приложениях путем условной компиляции различных базовых URL-адресов. Большую часть времени вы будете думать исключительно с точки зрения путей к ресурсам после того, как вы перешли за пределы инициализации библиотеки.
Пример:
1
2
|
RKClient* client = [RKClient clientWithBaseURL:@»http:///restkit.org»];
[client get:@»/foo/bar.json» delegate:self];
|
- Отображение объектов. Когда вы используете RestKit для моделирования удаленных ресурсов в локальные объекты, вы будете взаимодействовать со слоем отображения объектов. Сопоставление объектов — это процесс получения удаленной полезной нагрузки JSON (или другого проводного формата), ее синтаксического анализа в графе, соответствующем кодированию значений ключей, соответствующего NSObject, и применения набора правил сопоставления для преобразования значений внутри графа анализируемого объекта в атрибуты модели. объект. RestKit поддерживает расширенное отображение помимо того, что вы получаете от простого декодирования полезной нагрузки, такого как анализ строки, содержащей дату, в свойстве NSDate и доступ к данным с помощью операторов кодирования значения ключа. Правила отображения объектов настраиваются путем реализации метода elementToPropertyMappings протокола RKObjectMappable :
Пример:
01
02
03
04
05
06
07
08
09
10
11
12
|
@implementation MyObject
// Map full_name and street_adddress in JSON payload to
// local properties fullName and streetAddress
+ (NSDictionary*)elementToPropertyMappings {
return [NSDictionary dictionaryWithKeysAndObjects:
@»full_name», @»fullName»,
@»street_address», @»streetAddress»,
nil];
}
@end
|
- Маршрутизация. Система маршрутизации отвечает за генерацию путей к ресурсам из экземпляров локальных объектов. Это позволяет вам манипулировать и синхронизировать ваши локальные объекты с их удаленными представлениями, даже не видя URL. Система маршрутизации расширяема за счет предоставления собственной реализации протокола RKRouter, но RestKit поставляется с мощной реализацией в классе RKDynamicRouter. Динамический маршрутизатор позволяет вам кодировать имена свойств в простых строках, чтобы генерировать сложные пути к ресурсам во время выполнения. Это легче всего понять на нескольких примерах:
Пример:
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
27
28
29
30
31
32
33
|
RKObjectManager* manager = [RKObjectManager objectManagerWithBaseURL:@»http://restkit.org»];
RKDynamicRouter* router = [[RKDynamicRouter new] autorelease];
manager.router = router;
// Send POST requests for instances of Article to ‘/articles’
[router routeClass:[Article class] toResourcePath:@»/articles» forMethod:RKRequestMethodPOST];
// Configure a default resource path for Articles.
// articleID is a property on the Article class
[router routeClass:[Article class] toResourcePath:@»/articles/(articleID)»];
// Configure Comments on the Article.
// where the Comment has a relationship to an Article.
[router routeClass:[Comment class] toResourcePath:@»/articles/(article.articleID)/comments» forMethod:RKRequestMethodPOST];
// Let’s create an Article
Article* article = [Article object];
article.title = @»Foo»;
article.body = @»This is the body»;
// Send a POST to /articles to create the remote instance
[[RKObjectManager sharedManager] postObject:article delegate:self];
// Now let’s create a Comment on the Article
Comment* comment = [Comment object];
comment.article = article;
comment.body = @»This is the comment!»;
// Given Article has an ID of 1234, will send a POST to /articles/1234/comments to create the Comment
[[RKObjectManager sharedManager] postObject:comment delegate:self];
// Delete the Article.
[[RKObjectManager sharedManager] deleteObject:comment delegate:self];
|
Вывод
В этой статье были изучены основы работы с RestKit. Теперь вы должны иметь четкое представление об основных концепциях и чувствовать себя хорошо подготовленными, чтобы приступить к созданию вашего следующего приложения RESTful для iOS. Как мы упоминали во вводном разделе, RestKit также включает в себя некоторые расширенные функции, которые не были рассмотрены в этой статье. Мы подробно рассмотрим расширенные части библиотеки, включая Core Data, в нашем следующем расширенном руководстве. До этого вы можете узнать больше из примера кода, включенного в библиотеку, и изучения ресурсов ниже.