Обзор функций платформы iOS
На этой странице перечислены последние выпуски iOS, а также выделены некоторые платформы Apple, к которым можно получить доступ с помощью Xamarin.iOS.
Выпуски iOS
| Выпуск | Описание |
|---|---|
| Введение в iOS 14 | В этом документе описывается Xamarin.iOS 14. |
| Введение в iOS 13 | В этом документе описывается Xamarin.iOS 13. |
| Введение в iOS 12 | В этом документе описываются функции iOS 12, доступные для использования при создании приложений Xamarin.iOS. |
| Введение в iOS 11 | В этом документе описываются новые и обновленные функции в iOS 11 и Xcode 9, такие как ARKit, Core ML, Core NFC, Drag and Drop, MapKit, PDFKit, SiriKit и Vision. В нем содержатся ссылки на руководства, описывающие использование этих функций с Xamarin.iOS. |
| Введение в iOS 10 | IOS 10 включает несколько новых API и служб, которые позволяют разрабатывать приложения с новыми функциями и функциями. В iOS 10 приложения обладают новыми возможностями, такими как расширение карт, сообщений, телефонов и Siri. В этом разделе показано, как воспользоваться преимуществами этих функций в приложении Xamarin.iOS. |
| Введение в iOS 9 | В этом разделе описываются изменения, внесенные в iOS 9 при обновлении с iOS 8, и способы использования этих функций в приложении Xamarin.iOS. |
| Введение в iOS 8 | iOS 8 внесла большое количество изменений в операционную систему с iOS 7. Здесь мы покажем, что это такое и как их использовать. |
| Введение в iOS 7 | Основные новые API, появившиеся в iOS 7, включая переходы контроллера представления, улучшения анимации UIView, UIKit Dynamics и Text Kit. |
| Введение в iOS 6 | Описание возможностей, представленных в iOS 6, включая представления коллекций, комплект pass kit, набор событий и социальную платформу. |
Apple Pay
Apple Pay была представлена наряду с iOS 8, что позволяет пользователям платить за физические товары, такие как продукты питания, развлечения и членство, через свои устройства iOS. Он доступен на iPhone 6 и iPhone 6 Plus, а также может быть сопряжен с Apple Watch для покупок в магазине. При использовании на iPhone он использует Touch ID для подтверждения и авторизации транзакций на счете или дебетовой карта пользователя.
CallKit
Новый API CallKit в iOS 10 позволяет приложениям VOIP интегрироваться с пользовательским интерфейсом iPhone и предоставлять пользователям знакомый интерфейс и интерфейс. С помощью этого API пользователи могут просматривать вызовы VOIP с экрана блокировки устройства iOS и взаимодействовать с ними, а также управлять контактами с помощью представлений Избранное и Последние .
Контакты и ContactsUI
С появлением iOS 9 компания Apple выпустила две новые платформы, и ContactsUI , которые заменяют существующие платформы пользовательского интерфейса адресной книги и адресной книги, Contacts используемые в iOS 8 и более ранних версиях.
Средство выбора документов
Средство выбора документов позволяет совместно использовать документы между приложениями. Эти документы могут храниться в iCloud или в другом каталоге приложения. Доступ к документам осуществляется через набор расширений поставщика документов, установленных пользователем на своем устройстве.
EventKit
В iOS есть два встроенных приложения, связанных с календарем: приложение календаря и приложение напоминаний. Это достаточно просто, чтобы понять, как приложение календаря управляет данными календаря, но приложение напоминаний менее очевидно. Напоминания на самом деле могут содержать даты, связанные с ними с точки зрения того, когда они должны быть выполнены, и т. д. Таким образом, iOS хранит все данные календаря, будь то события календаря или напоминания, в одном расположении, которое называется база данных календаря.
Расширения iOS
Расширения, представленные в iOS 8, являются специализированными UIViewControllers , которые представлены iOS в стандартных контекстах, таких как центр уведомлений, как пользовательские типы клавиатуры, запрашиваемые пользователем для выполнения специализированных входных данных или другие контексты, такие как редактирование фотографии, где расширение может предоставлять специальные фильтры эффектов.
Графика и анимация в iOS
Графика и анимация в iOS охватывает основные графические понятия в iOS, такие как CoreImage, Базовая графика и Базовая анимация.
перемещение вручную;
Компания Apple представила Handoff в iOS 8 и OS X Yosemite (10.10), чтобы предоставить пользователю общий механизм передачи действий, начатых на одном из своих устройств, на другое устройство, на котором выполняется то же приложение или другое приложение, поддерживающее то же действие.
HealthKit
Health Kit предоставляет безопасное хранилище данных для сведений, связанных со здоровьем пользователя. Приложения Health Kit могут с явного разрешения пользователя читать и записывать данные в это хранилище данных, а также получать уведомления при добавлении соответствующих данных. Приложения могут предоставлять данные, или пользователи могут использовать приложение Apple Health для просмотра панели мониторинга всех своих данных.
HomeKit
Компания Apple представила HomeKit в iOS 8, чтобы обеспечить общую платформу для обнаружения и взаимодействия с устройствами домашней автоматизации в доме пользователя. HomeKit предоставляет общую платформу для настройки устройств и настройки действий для управления ими.
Покупка из приложения
Приложения iOS могут продавать цифровые продукты или услуги с помощью StoreKit — набора API,предоставляемых iOS, которые взаимодействуют с серверами Apple для проведения финансовых транзакций с пользователем через свой идентификатор Apple ID. API StoreKit в первую очередь связаны с получением сведений о продукте и проведением транзакций. Компонент пользовательского интерфейса отсутствует. Приложения, реализующие покупку из приложения, должны создавать собственный пользовательский интерфейс и отслеживать приобретенные элементы с помощью пользовательского кода для предоставления пользователю необходимых продуктов или служб.
API игр iOS
Компания Apple внесла несколько технологических усовершенствований в интерфейсы API игр в iOS 9, которые упрощают реализацию игровой графики и звука в приложении Xamarin.iOS. К ним относятся простота разработки с помощью высокоуровневых платформ и использование возможностей GPU устройства iOS для повышения скорости и графических возможностей.
Интеграция с приложением сообщений
Расширение приложения для сообщений в iOS 10 интегрируется с приложением «Сообщения» и предоставляет пользователю новые функциональные возможности. Расширение может отправлять текст, наклейки, файлы мультимедиа и интерактивные сообщения.
Многозадачность для iPad
в iOS 9 добавлена поддержка многозадачности для запуска двух приложений одновременно на определенном оборудовании iPad. Многозадачность для iPad поддерживается с помощью следующих функций: Slide Over, Split View & Picture in Picture.
PassKit
Passbook — это приложение для iPhone и iPod touches с iOS 6. Он хранит и отображает штрихкоды и другую информацию, чтобы связать транзакции клиентов на их телефоне с «реальным миром». Пропуска создаются продавцами и отправляются клиенту по электронной почте, URL-адресам или из собственного приложения продавца iOS. Passbook хранит и упорядочивает все pass на телефоне, а также отображает напоминания pass на экране блокировки в зависимости от даты и времени или расположения устройства.
В этом документе описано, как использовать API Pass Kit с Xamarin.iOS, а также описано, как реализовать pass на сервере.
PhotoKit
Photo Kit — это новая платформа, которая позволяет приложениям запрашивать системную библиотеку образов и создавать пользовательские интерфейсы для просмотра и изменения ее содержимого. Он включает в себя ряд классов, представляющих ресурсы изображений и видео, а также коллекции ресурсов, таких как альбомы и папки.
Запрос проверки приложения
Не знакомый с iOS 10.3, RequestReview() метод позволяет приложению iOS запрашивать у пользователя оценку или просмотр. При вызове этого метода в приложении доставки, которое пользователь установил из App Store, iOS 10 будет обрабатывать весь процесс оценки и проверки для разработчика. Так как этот процесс регулируется политикой App Store, оповещение может отображаться или не отображаться.
Интерфейсы API для поиска
Поиск был расширен в iOS 9, чтобы предоставить отличные новые способы доступа к информации и функциям в приложении Xamarin.iOS. Новые API поиска приложений делают содержимое приложения доступным для поиска в результатах поиска Spotlight и Safari, а также в напоминаниях и предложениях Siri. Это позволяет пользователям быстро получать доступ к действиям и сведениям в приложении.
SiriKit
SiriKit, не знакомый с iOS 10, позволяет приложению iOS предоставлять службы, доступные пользователю с помощью Siri, и приложение «Карты» на устройстве iOS с помощью расширений приложений и новых платформ пользовательского интерфейсаIntents and Intents.
Социальная платформа
Social Framework предоставляет единый API для взаимодействия с социальными сетями, включая Twitter и Facebook, а также SinaWeibo для пользователей в Китае.
Распознавание речи
iOS 10 включает новый API службы «Речь», который позволяет приложению поддерживать непрерывное распознавание речи и транскрибировать речь (из динамических или записанных аудиопотоков) в текст.
TextKit
Text Kit — это новый API, который предлагает мощные функции разметки и отрисовки текста. Он основан на низкоуровневой платформе Core Text, но его гораздо проще использовать, чем основной текст.
Трехмерные сенсорные технологии
В этой статье содержатся сведения об использовании новых интерфейсов API 3D Touch для добавления жестов, чувствительных к давлению, в приложения Xamarin.iOS, которые работают на новых устройствах iPhone 6s и iPhone 6s Plus.
Touch ID и Face ID с Xamarin.iOS
Touch ID и Face ID — это системы биометрической проверки подлинности, доступные с iOS 8. В этой статье и образце описано, как использовать Touch ID и Face ID с Xamarin.iOS.
Уведомления для пользователей
Впервые в iOS 10 платформа уведомлений пользователей позволяет выполнять доставку и обработку локальных и удаленных уведомлений. Используя эту платформу, приложение или расширение приложения может запланировать доставку локальных уведомлений, указав набор условий, таких как расположение или время суток.
Широкая цветовая палитра
IOS 10 и macOS Sierra расширяет поддержку форматов пикселей с расширенным диапазоном и цветовых пространств в широкой гамме в системе, включая такие платформы, как Core Graphics, Core Image, Metal и AVFoundation. Поддержка устройств с широкоцветными дисплеями еще больше упрощается за счет обеспечения такого поведения во всем графическом стеке.
Привязки Objective-C
При работе в iOS могут возникнуть случаи, когда требуется использовать стороннюю Objective-C библиотеку. В таких ситуациях можно использовать проекты привязки MonoTouch для создания привязки C# к собственным Objective-C библиотекам. В проекте используются те же средства, которые используются для переноски API iOS в C#. В этом документе описывается привязка Objective-C API.
Привязка библиотек Swift для iOS
В этом документе описывается создание привязок C# к коду Swift, что позволяет использовать собственные библиотеки и CocoaPods в приложении Xamarin.iOS.
Ссылки на собственные библиотеки
Xamarin.iOS поддерживает связывание как с собственными библиотеками C, так и Objective-C с библиотеками. В этом документе описывается, как связать собственные библиотеки C с проектом Xamarin.iOS.
Внедренные платформы
Объясняется, как внедрить Objective-C пользовательские платформы в приложения Xamarin.iOS.
Ещё о прошивке магнитолы и оффлайн-картах в Я.Навигаторе

Езжу с прошивкой уже с 13 мая, в целом прошивкой доволен, прошивка — компромисс, как я и писал из прошлого поста. Но, функционал приличный, что ещё кстати можно сделать благодаря прошивке:
1. Полностью отключить систему Start/Stop при запуске двигателя.
2. Сделать кнопку паузы на качельке громкости на руле.
3. Автоматическое открытие шторки панорамной крыши при запуске двигателя.
Мелочи а приятно, для многих я думаю это будет удобно! Собственно это я и сделал. Ещё попробовал приложение 7Fon для смены фонов рабочего стола. Тоже круто!

Но сейчас снова коснёмся негативных моментов, и для кого-то важных, скорее всего. Но! Весь этот негатив можно решить очень просто, приложив несколько усилий. Этим мы и займемся.
А речь у нас пойдет про оффлайн-карты в Яндекс Навигаторе, дело в том, что версия которая у нас стабильно работает и без вылетов, это версия 3.6.8, она старая — 2019 года, но в целом жить с ней можно, но есть негативный момент в том, что она НЕ скачивает оффлайн-карты, просто вылетает! Да, кто-то скажет: да кому они нужны? кругом интернет и т.д. и т.п. Но он будет не прав в том, что иногда ты можешь ехать по непонятной трассе или жить где-то в посёлке, где с сетью могут быть достаточно серьёзные проблемы, и ландшафт на экране в один неподходящий момент просто закончится, и это доставит сильные неудобства и приведёт нас в полную «небоеготовность», но в этом не наш смысл и не наша стратегия!

Поэтому, посидев подумав как можно решить проблему с оффлайн-картами, пришёл к выводу что решать ее нужно с помощью эмулятора Андроид на ПК и флешки. Почему использую эмулятор? Потому что Android 13 на телефоне уже не поддерживает эту версию яндекс навигатора… Приходится делать через него.
Что нам нужно для скачивания оффлайн-карт во внутреннюю память магнитолы, да ещё так, чтобы Яндекс Навигатор их видел?
1) Компьютер под Windows или macOS.
2) Эмулятор Android — BlueStacks
3) .APK-файл установщик Яндекс Навигатора версии 3.6.8 *тыц*
4) Съемный накопитель (флешка) на 4+ ГБ.
— Для чего делать такой путь? Можно же просто перетащить карты с мобилки на Андроиде и вуаля!
— Да вот тут то не задача, в старых версиях Яндекс Навигатора путь к картам и их название совершенно другое, и отличается от новых версий, если их приложить в папки то ничего не произойдет! Приложение их просто не увидит.
Поэтому, для исследования пути, нам и нужен такой гемор, и чтобы правильно выгрузить карты и загрузить их на накопитель, а потом уже через Root Explorer забросить в папку где хранит данные навигатор.
И так, скачиваем и устанавливаем BlueStacks.

После его установки, запускаем его, либо запускаем скачанный .apk файл и ждём пока он установится. Затем уже открываем Яндекс Навигатор.

Дальше, идём в меню с тремя черточками, находим там пункт — Загрузка карт.

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



Общий путь который нам нужен в блюстаксе: /sdcard/Android/data/ru.yandex.yandexnavi/files/mapkit


В этих папках как раз и хранятся наши скачанные только что карты, их нам нужно переместить изначально на рабочий стол компа.
Так как, проводник этот в Блюстаксе какой-то кривой и кастрированный, папки копировать он не умеет, то получается нужно копировать из каждой папки всё пофайлово. Так что, создаем папки так же как в Bluestacks, и копируем все в точности.


Сравниваем потом все папки и каждый файл, чтобы все было 1:1.
Затем можно все закрывать, и доставать флешку, и копировать папку mapkit на неё.
Далее, идём в машину.
Подключаем флешку со скопированной папкой, и открываем Root Explorer.
Там, идём по тому же самому пути, только в меню выберите — Закладки — Память. И у Вас откроется окно с папками плюс-минус похожее как в блюстаксе.
В первом диалоговом окне идём вот по этому пути: /Android/data/ru.yandex.yandexnavi/files/
И так же, во втором диалоговом окне находим на флешке папку mapkit, выделяем и нажимаем Копировать.
И соответственно копируем её в /Android/data/ru.yandex.yandexnavi/files/.
И в целом всё, останется лишь открыть Яндекс Навигатор, выбрать Меню — Настройки — Сохраненные данные и указать что папка хранения карт — Карта памяти.
И в целом всё, потом у нас появятся загруженные карты, которые работают без наличия интернета!


Если кто-то найдёт способ проще, только поприветствую! Я думаю многим будет эта информация очень и очень полезна!
Путь с указателями направления на карте с использованием Yandex Map Kit для Android
Загружаем архив с библиотекой отсюда и получаем API-ключ.
Создаем проект в Eclipse, копируем с заменой папки \yandexmapkit-library\res и \yandexmapkit-library\libs из загруженного архива в папку нашего проекта.
В настройках проекта добавляем ссылку на yandexmapkit-android.jar из папки libs нашего проекта (Build Path->Configure Buil Path->Libraries->Add External JARs)
Добавляем разрешения в манифест нашего проекта
Изменяем разметку activity
2. Создание расширения для класса Overlay с целью вывода на карту пути с указателями направления и обработки событий «onClick» по карте
Чтобы нарисовать путь, нам потребуется расширить класс OverlayIRender, который реализует интерфейс IRender
public class MyOverlayIRender extends OverlayIRender < Overlay mOverlay; public MyOverlayIRender(Overlay overlay) < super(); mOverlay = overlay; >@Override public void draw(Canvas canvas, OverlayItem arg1) < super.draw(canvas, arg1); Listoi = mOverlay.getOverlayItems(); if (oi.size() < 2) return; Paint mPaint = new Paint(); mPaint.setDither(true); mPaint.setColor(Color.RED); mPaint.setStyle(Paint.Style.FILL_AND_STROKE); mPaint.setStrokeJoin(Paint.Join.ROUND); mPaint.setStrokeCap(Paint.Cap.ROUND); mPaint.setStrokeWidth(2); mPaint.setAntiAlias(true); for (int i = 0; i < oi.size() - 1; i++) < Path path = new Path(); ScreenPoint p1 = mOverlay.getMapController().getScreenPoint( oi.get(i).getGeoPoint()); ScreenPoint p2 = mOverlay.getMapController().getScreenPoint( oi.get(i + 1).getGeoPoint()); float angle = (float) (Math.atan2(p2.getY() - p1.getY(), p2.getX()- p1.getX()) * 180 / 3.14); path.moveTo(p2.getX(), p2.getY()); path.lineTo(p1.getX(), p1.getY()); canvas.drawPath(path, mPaint); canvas.save(); canvas.rotate(angle + 90, p2.getX(), p2.getY()); Path path2 = new Path(); path2.moveTo(p2.getX(), p2.getY()); path2.lineTo(p2.getX() + 5, p2.getY() + 8.66f); path2.lineTo(p2.getX() - 5, p2.getY() + 8.66f); path2.close(); canvas.drawPath(path2, mPaint); canvas.restore(); >> >
Если количество точек добавленных в наш путь больше 1, то в цикле отрисовываются отрезки пути и стрелки направления.
Теперь нужно создать наследника Overlay MyPathOverLay, назначить ему MyOverlayIRender для отрисовки.
public class MyPathOverLay extends Overlay < MapView mMmapView; public MyPathOverLay(MapController arg0, MapView mapView) < super(arg0); mMmapView = mapView; this.setIRender(new MyOverlayIRender(this)); >@Override public int compareTo(Object arg0) < return 0; >@Override public boolean onLongPress(float x, float y) < OverlayItem m = new OverlayItem( this.c.getGeoPoint(new ScreenPoint(x, y)), BitmapFactory.decodeResource( this.c.getContext().getResources(), R.drawable.flag2leftred)); m.setOffsetY(-23); this.addOverlayItem(m); this.c.setPositionNoAnimationTo(this.c .getGeoPoint(new ScreenPoint(x, y))); return true; >>
В переопределенном методе onLongPress будем добавлять промежуточные точки для нашего пути долгим нажатием на карту.
R.drawable.flag2leftred — картинка для точки,
m.setOffsetY(-23); — смещение, которое нужно подобрать, если нужно сместить картинку относительно точки нажатия на карту, по-умолчанию центр картинки совмещается с точкой нажатия.
Осталось добавить наш Overlay на карту и протестировать
public class BlogYandexActivity extends Activity < @Override public void onCreate(Bundle savedInstanceState) < super.onCreate(savedInstanceState); setContentView(R.layout.main); MapView mMap = (MapView) findViewById(R.id.map); MapController mMapController = mMap.getMapController(); OverlayManager mOverlayManager = mMapController.getOverlayManager(); mOverlayManager.addOverlay(new MyPathOverLay(mMapController, mMap)); mMap.showBuiltInScreenButtons(true); mOverlayManager.getMyLocation().setEnabled(false); >>

- Android разработка
- Yandex Map Kit
- direction arrow
- onclick
- onlongpress
- overlay
- pathoverlay
- нажатие на карту
- путь на карте
- стрелки направления
Туториал по фреймворку Realm
Realm — это решение для кросс-платформенной мобильной базы данных, разработанное специально для мобильных приложений.
Он быстрый, легкий, его очень просто интегрировать в свой проект. Наиболее часто используемые функции, такие как запросы к базе данных, состоят из одной строчки кода!
В отличие от оболочек вокруг Core Data, таких как MagicalRecord, Realm не зависит от Core Data или даже от SQLite бэкэнда. Разработчики Realm утверждают, что их решение для хранения данных быстрее, чем даже SQLite и Core Data.
Вот пример кода Core Data для извлечения набора записей с предикатом, а затем сортировки результатов:
let fetchRequest = NSFetchRequest(entityName: "Specimen") let predicate = NSPredicate(format: "name BEGINSWITH [c]%@", searchString) fetchRequest.predicate = predicate let sortDescriptor = NSSortDescriptor(key: "name", ascending: true) fetchRequest.sortDescriptors = [sortDescriptor] do < let results = try managedObjectContext?.executeFetchRequest(fetchRequest) >catch
То, что занимает довольно много строк кода с использованием Core Data, может быть достигнуто гораздо меньшим количеством строк в Realm:
let predicate = NSPredicate(format: "name BEGINSWITH [c]%@", searchString); do < let specimens = try Realm().objects(Specimen).filter(predicate).sorted("name", ascending: true) >catch
Преимуществом работы с более сжатым кодом Realm является то, что писать и читать ваш код становится гораздо проще.
Этот туториал по Realm познакомит вас с основными функциями Realm на iOS. Вы узнаете, как начать работать с фреймворком Realm, создавать модели, выполнять запросы и обновлять записи.
Поехали!
Вот вам сценарий: вас приняли на работу в качестве стажера в National Park Service (Службу Национальных Парков), и ваша работа состоит в документировании видов, обитающих в самых больших национальных парках в Соединенных Штатах. Вам нужен помощник для хранения ваших заметок и документировании выводов, но агентство не может вам его предоставить из-за экономии. Вместо этого, вы решаете создать виртуального помощника себе сами — приложение под названием “Agents Partner” ( «Партнерское агенство”).
Загрузите стартовый проект этого туториала здесь: AgentsPartner_Starter.
Откройте стартовый проект в Xcode. MapKit в вашем проекте уже установлен. На этом этапе ваше приложение содержит только экземпляры UITableView и MKMapView для обеспечения работоспособности используемых карт.
Заметка
Если вы хотите получить дополнительную информацию о MapKit, начните с Копошилка: MapKit, где есть дополнительная информация по работе с MapKit.
Стартовый проект не содержит Realm, так что пришло время его добавить.
Заметка
Данный туториал был написан с Realm 0.98.0
Отличный способ установить Realm — это сделать это с CocoaPods. CocoaPods является менеджером зависимостей в проектах Cocoa на Swift и Objective-C, он содержит тысячи библиотек, которые вы можете скачать и использовать в собственных проектах.
Заметка
Если вы не знакомы с CocoaPods или вам необходима помощь с его установкой, то Вы можете посмотреть пример работы с CocoaPods в видео при работе со сторонней библиотекой SwiftyJSON.
Создайте файл с именем ‘Podfile’ в корневой директории стартового проекта (Для этого в командной строке просто используйте команду touch Podfile). Скопируйте следующий фрагмент текста и вставьте его в Podfile:
platform :ios, ‘9.0’ use_frameworks! target ‘Agents Partner’ do pod 'RealmSwift', '~> 0.98' end
Сохраните и закройте ваш Podfile. Затем снова в командной строке, в корневом каталоге вашего проекта (то же местоположение, в котором находится ваш Podfile), запустите команду pod install. Она сообщает CocoaPods, что нужно просканировать Podfile и установить модули, которые перечислены в вашем Podfile. Вот так! Установка Realm может занять несколько минут, и как только она будет завершена, вы увидите строку в нижней части экрана, начинающуюся с Pod installation complete!
Откройте корневой каталог стартового проекта в Finder, и в нем вы увидите папки, которые разместил здесь CocoaPods, в дополнение к Agents Partner.xcworkspace. Если Ваш стартовый проект Agents Partner уже открыт в Xcode, закройте его, а затем двойным щелчком откройте файл .xcworkspace. Именно этот файл вы будете открывать далее при работе над этим проектом. Если вы по ошибке откроете обычный файл проекта, Xcod не сможет найти какие-либо dependencies, установленные вами через CocoaPods, так что вы должны использовать файл .xcworkspace. Разверните проект Agents Partner в Project navigator, а затем и группу/ папку, также называемую Agents Partner для того, чтобы увидеть файлы, с которыми вы будете работать.
Вот так! Запустите проект, чтобы удостовериться, что все компилируется. Если нет, то проверьте еще раз правильно ли вы сделали описанные выше шаги. Вы должны увидеть основной экран:

Браузер Realm’а
У Realm также есть хорошая утилита, и вам нужно ее установить из App Store, она сделает вашу жизнь немного легче.
Realm Browser позволяет читать и редактировать базы данных Realm. Это вам сильно поможет при разработке, так как формат базы данных Realm является их собственностью и его трудно «прочитать» человеку. Скачать его здесь.

Концепции и основные классы
Для того, чтобы лучше понять, что именно делает Realm, вот обзор классов Realm и понятий, которые вы будете использовать в этом уроке:
Realm: экземпляры Realm — это сердце фреймворка, это ваша точка доступа к основной базе данных, аналогично управляемому контексту объекта в Core Data. Вы будете создавать экземпляры при помощи инициализатора Realm().
Object (Объект): Это ваша модель Realm. Процесс создания модели определяет схему базы данных. Для того, чтобы создать модель вы просто создаете подкласс Object и определяете fields (поля), которые вы хотите сохранить как свойства.
Relationships (Связи или отношения): Вы создаете связь one-to-many (один ко многим) между объектами, просто объявляя свойство типа Object, на которое вы хотите ссылаться. Вы можете создать связь многие-к-одному и многие-ко-многим через свойство типа List, что приводит вас к …
Write Transactions (Запись операций): Любые операции в базе данных, такие как создание, редактирование или удаление объектов, должны выполняться в рамках операций writes, которые происходят с помощью вызова write(_:) у экземляров Realm.
Queries (Запросы): Для извлечения объектов из базы данных вам нужно использовать запросы. Самая простая форма запроса — это вызов objects() у экземпляра Realm, передавая класс Object, который вы ищете. Если ваши поисковые запросы являются более сложными, вы можете использовать предикаты, выстраивая запросы, и также организуя результаты поиска.
Results (Результаты): Результаты — это автоматически обновляемый тип контейнера, который вы получаете в ответ на объектные запросы. У них много общего с обычными массивами, в том числе синтаксис сабскрипта для захвата элемента в индексе.
Теперь, когда вы познакомились с Realm, пришло время взяться за остальную часть проекта этого туториала.
Создание первой модели
Откройте Specimen.swift из группы Models и добавьте следующую реализацию:
import Foundation import RealmSwift class Specimen: Object
Этот код добавляет несколько свойств: name и specimenDescription, хранящий имя и описание вида. Конкретные типы данных в Realm, такие как строки, должны быть инициализированы со значением. В этом случае вы инициализируете их с пустой строкой.
latitude (широта) и longitude (долгота) содержат координаты вида. Здесь вы устанавливаете тип на Double и инициализируете их с 0.0.
И, наконец, created хранит дату создания экземпляра. NSDate() возвращает текущую дату, так что вы можете инициализировать свойство с этим значением.
Теперь, когда вы создали свою первую модель в Realm, как вы смотрите на то, чтобы попытаться реализовать полученные знания?
Экземпляры будут разделены на различные категории. Задача состоит в том, чтобы самостоятельно создать модель Category, задать имя файлу Category.swift и задать вашей новой модели только один String свойства name.
Это будет реализовано так:
import Foundation import RealmSwift class Category : Object
Теперь у вас есть модель Category, которую вам нужно связать каким-то образом с моделью Specimen.
Вспомним, что в примечании выше сказано, что вы можете создать связи между моделями, просто объявив свойства с соответствующей моделью, с которой нужна связь.
Откройте Specimen.swift и добавьте следующее объявление ниже других свойств:
dynamic var category: Category!
Это устанавливает связь один-ко-многим между Specimen и Category. Это означает, что каждый Specimen может принадлежать только к одной Category, но каждая Category может иметь много Specimen.
Теперь, когда ваши основные модели данных на месте — пришло время добавить записи в базу данных!
Добавление записей
Когда пользователь добавляет новый вид, то они могут войти в имя вида и выбрать ему категорию. Откройте CategoriesTableViewController.swift. Во вью контроллере будет список категорий в виде таблицы, чтобы пользователь мог выбрать.
Перед тем как начать писать код для того, чтобы интегрировать Realm в этот вью контроллер, необходимо сначала импортировать фрейворк RealmSwift в этот исходный файл. Добавьте следующую строчку в верхнюю часть файла, чуть ниже import UIKit:
import RealmSwift
Вам нужно заполнить этот table view некоторыми дефолтными категориями. Вы можете хранить эти экземпляры Category в экземпляре Results.
У CategoriesTableViewController есть массив categories, использующийся на данном этапе как массив-плейсхолдер. Найдите следующий код в верхней части определения класса:
var categories = []
и замените его следующими строчками:
let realm = try! Realm() lazy var categories: Results = < self.realm.objects(Category) >()
Когда вам нужно получить объекты, вы должны определить, какие модели вы хотите получить. В приведенном выше коде сначала создается экземпляр Realm, а затем заполняется categories через вызов objects(_:), передавая имени класса тип модели, который вам нужен.
Заметка
Для упрощения кода, необходимого для этого туториала, вы будете использовать try! при вызове методов Realm, которые будут выбрасывать ошибку. Когда вы будете писать код самостоятельно, вам нужно будет писать try и do/catch для вылавливания ошибок и соответствующим образом их обрабатывать.
Вам нужно дать пользователю несколько категорий по умолчанию, чтобы он мог из них выбирать, первый раз запуская приложение.
Добавьте следующий вспомогательный метод для определения класса ниже preferredStatusBarStyle:
func populateDefaultCategories() < if categories.count == 0 < // 1 try! realm.write() < // 2 let defaultCategories = ["Birds", "Mammals", "Flora", "Reptiles", "Arachnids" ] // 3 for category in defaultCategories < // 4 let newCategory = Category() newCategory.name = category self.realm.add(newCategory) >> categories = realm.objects(Category) // 5 > >
- Если count здесь равно 0 — это означает, что база данных не имеет записей Category, как в случае, когда вы запускаете приложение в первый раз.
- Это часть начинает транзакцию с realm — теперь вы готовы добавить записи в базу данных.
- Здесь вы создаете список дефолтных имен категорий и затем проводите через них итерацию.
- Для каждого названия категории, вы создаете новый экземпляр Category, заполняете name и добавляете объект в realm.
- И, наконец, вы запрашиваете все категории, которые вы создали и храните их в categories.
Добавьте следующую строчку в конец viewDidLoad():
populateDefaultCategories()
Это вызывает вспомогательный метод для заполнения тестовых категорий, когда загружается вью.
Теперь, когда у вас есть данные, вам необходимо обновить методы источника данных тейбл вью для отображения категорий. Найдите tableView(_:cellForRowAtIndexPath:) и замените метод следующей реализацией:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
Эта реализация извлекает категорию из categories по индексу indexPath.row, а затем устанавливает значение ярлыка ячейки, чтобы показать свойство name категории.
Добавьте это свойство ниже других свойств, только что добавленных вами в CategoriesTableViewController:
var selectedCategory: Category!
Вы будете использовать это свойство для хранения выбранной Category.
Найдите tableView(_:willSelectRowAtIndexPath:) и замените весь метод следующим текстом:
override func tableView(tableView: UITableView, willSelectRowAtIndexPath indexPath: NSIndexPath) -> NSIndexPath
Теперь это будет хранить выбор пользователя в свойстве, которое вы объявили выше.
Увеличьте масштаб и выберите на карте что-то интересное, создайте новую аннотацию, нажав на кнопку + в верхнем правом углу. Нажмите на иконку на карте, чтобы выбрать позицию, а затем нажмите на данные аннотаций для внесения изменений. Затем нажмите на текстовое поле Category, чтобы увидеть список категорий, как показано ниже:

Вы можете выбрать категорию, но она будет только хранить его в свойстве, а не где-то в базе данных. То, что вы видите отображение категорий в приложении — это хорошо, но нам нужно увидеть записи в базе данных. Вы можете сделать это с помощью Realm Browser.
Работа с Realm Browser
На этом этапе что вы не знаете, так это где “живет” ваша база данных Realm. С помощью небольшой уловки вы сможете ее найти.
Откройте MapViewController.swift и импортируйте фреймворк RealmSwift. Добавьте следующую строчку в верхнюю часть файла, чуть ниже существующих выражений import в верхней части файла:
import RealmSwift
Теперь добавьте следующую строчку в viewDidLoad() сразу после вызова super.viewDidLoad():
print(Realm.Configuration.defaultConfiguration.path!)
Эта строчка просто указывает расположение базы данных в консоли дебаггера. После этого небольшого шага, загружаем базу данных с помощью Realm Browser.
Запустите приложение; вы увидите, что оно сообщит вам местонахождение базы данных в консоли Xcode.
Самый простой путь к папке с базой данных — это открыть Finder, нажать Cmd-Shift-G и вставить тот путь, который вам сообщит приложение.
После того, как вы откроете папку в Finder, вы увидите там один или два файла. Один из них default.realm — это ваш файл с базой данных. Второго файла возможно и не будет, это default.realm.lock, который не дает видоизменяться базе данных из-за других приложений, в то время когда она используется.
Если вы еще не загрузили Realm Browser, скачать его прямо сейчас из Mac App Store. Двойной клик на default.realm откроет его через Realm Браузер:

После того, как база данных будет открыта в Realm браузере, вы увидите Category с цифрой 5 напротив. Это означает, что класс содержит пять записей. Выберите класс для проверки отдельных полей, которые содержаться внутри.

Добавление категорий
Теперь вы можете реализовать логику, установив category Specimen.
Откройте AddNewEntryController.swift и импортируйте фреймворк RealmSwift. Еще раз импортируйте Realm в верхней части файла, чуть ниже существующих выражений импорта:
import RealmSwift
Теперь добавьте следующее свойство к классу:
var selectedCategory: Category!
Вы будете использовать этот класс для сохранения выбранной категории.
Затем, найдите unwindFromCategories() и добавьте следующую реализацию:
if segue.identifier == "CategorySelectedSegue"
unwindFromCategories() вызывается, когда пользователь выбирает категорию из CategoriesTableViewController, которую вы создали ранее. Здесь вы получаете выбранную категорию, сохраняете ее локально в selectedCategory, а затем заполняете текстовое поле с названием категории.
Теперь, когда вы позаботились о категориях, можно создать свой первый Specimen!
Там же в AddNewEntryController.swift, добавьте еще одно свойство к классу:
var specimen: Specimen!
Это свойство будет хранить новый объект вида.
Затем добавьте вспомогательный метод классу ниже:
func addNewSpecimen() < let realm = try! Realm() // 1 try! realm.write < // 2 let newSpecimen = Specimen() // 3 newSpecimen.name = self.nameTextField.text! // 4 newSpecimen.category = self.selectedCategory newSpecimen.specimenDescription = self.descriptionTextField.text newSpecimen.latitude = self.selectedAnnotation.coordinate.latitude newSpecimen.longitude = self.selectedAnnotation.coordinate.longitude realm.add(newSpecimen) // 5 self.specimen = newSpecimen // 6 >>
Вот что делает код:
- Вы сначала получаете экземпляр Realm, как и раньше.
- Здесь вы начинаете транзакцию записи, чтобы добавить новый Specimen.
- Затем создается новый образец Specimen.
- Затем присваиваете значения Specimen. Значения поступают из полей ввода текста в пользовательском интерфейсе, выбранные категории, а также координаты с аннотаций на карте.
- Затем вы добавляете новые Specimen в Realm.
- И, наконец, вы назначаете новый Specimen вашему свойству specimen.
Вам будет нужен какой-то валидатор, чтобы убедиться, что все поля в вашем Specimen заполняются правильно. Метод validateFields() в AddNewEntryController
существует именно для этого, то есть он проверяет имя вида и описание. Так как вы только что добавили возможность назначать категорию виду, значит вам нужно также проверять и поле категории тоже.
Там же в AddNewEntryController.swift, найдите строку в validateFields(), которая выглядит следующим образом:
if nameTextField.text!.isEmpty || descriptionTextField.text!.isEmpty
Измените эту строку следующим образом:
if nameTextField.text!.isEmpty || descriptionTextField.text!.isEmpty || selectedCategory == nil
Это подтверждает, что все поля были заполнены, и что вы также выбрали категорию.
Затем добавьте следующий метод классу:
override func shouldPerformSegueWithIdentifier(identifier: String?, sender: AnyObject?) -> Bool < if validateFields() < addNewSpecimen() return true >else < return false >>
В приведенном выше коде, вы вызываете метод для проверки полей, и только в том случае, если все заполнено, вы добавляете новый образец.
Запустите приложение, нажмите кнопку +, чтобы создать новый Specimen. Введите имя и описание, выберите Category и нажмите Confirm, чтобы добавить Specimen в базу данных.

Вью контроллер освобождается, но ничего не происходит. В чем дело?
Да - вы разместили запись в вашем Realm, но вы еще не отметили на карте вновь созданный вид!
Получение записей
Теперь, когда вы добавили вид в базу данных, вам нужно, чтобы он появился на карте.
Во-первых, еще раз взгляните на обновленную базу данных в Realm Browser:

Вы видите ваш вид, со всеми заполненными полями, а также широту и долготу из MKAnnotation. Вы также увидите ссылку на категорию вашего вида - что означает, что ваша связь Category “один-ко-многим” работает, как и ожидалось. Выберите Category в вашей записи Specimen для просмотра самой записи Category.
Теперь вам нужно заполнить карту в приложении.
Откройте SpecimenAnnotation.swift и добавьте свойство к классу:
var specimen: Specimen?
Это будет держать образец для аннотации.
Затем замените инициализатор следующим текстом:
init(coordinate: CLLocationCoordinate2D, title: String, subtitle: String, specimen: Specimen? = nil)
Изменение заключается в том, что мы добавили возможность передачи Specimen. Вид будет иметь значение по умолчанию nil, что означает, что вы, если хотите, можете опустить этот аргумент. Это означает, что остальная часть приложения может продолжать вызывать инициализатор только с первыми тремя аргументами, как это и обычно и происходит без аргумента вида.
Теперь откройте MapViewController.swift, добавьте новое свойство классу:
var specimens = try! Realm().objects(Specimen)
Так как вы хотите сохранить коллекцию образцов в этом свойстве, вы просто запрашиваете экземпляр Realm для всех объектов типа Specimen.
Теперь вам будет нужен какой-то механизм для заполнения карты. Там же в MapViewController.swift добавьте следующий метод классу:
func populateMap() < mapView.removeAnnotations(mapView.annotations) // 1 specimens = try! Realm().objects(Specimen) // 2 // Create annotations for each one for specimen in specimens < // 3 let coord = CLLocationCoordinate2D(latitude: specimen.latitude, longitude: specimen.longitude); let specimenAnnotation = SpecimenAnnotation(coordinate: coord, title: specimen.name, subtitle: specimen.category.name, specimen: specimen) mapView.addAnnotation(specimenAnnotation) // 4 >>
- Во-первых, удалите все существующие аннотации на карте, чтобы начать с чистого листа.
- Далее, обнулите ваше свойство specimens.
- Затем вы перебираете specimens и создаете SpecimenAnnotation с координатами вида, его name и его category.
- И, наконец, вы добавляете каждый specimenAnnotation в MKMapView.
Теперь вам нужно откуда-то вызвать этот метод. Найдите viewDidLoad() и добавьте эту строку в конец реализации:
populateMap()
Это гарантирует то, что карта будет заполнена образцами всякий раз, когда загружается вью контроллер карты.
Наконец, вам нужно просто изменить вашу аннотацию и включить имя образца и категорию. Найдите unwindFromAddNewEntry(_:) и замените метод следующей реализацией:
@IBAction func unwindFromAddNewEntry(segue: UIStoryboardSegue) < let addNewEntryController = segue.sourceViewController as! AddNewEntryController let addedSpecimen = addNewEntryController.specimen let addedSpecimenCoordinate = CLLocationCoordinate2D(latitude: addedSpecimen.latitude, longitude: addedSpecimen.longitude) if let lastAnnotation = lastAnnotation < mapView.removeAnnotation(lastAnnotation) >else < for annotation in mapView.annotations < if let currentAnnotation = annotation as? SpecimenAnnotation < if currentAnnotation.coordinate.latitude == addedSpecimenCoordinate.latitude && currentAnnotation.coordinate.longitude == addedSpecimenCoordinate.longitude < mapView.removeAnnotation(currentAnnotation) break >> > > let annotation = SpecimenAnnotation(coordinate: addedSpecimenCoordinate, title: addedSpecimen.name, subtitle: addedSpecimen.category.name, specimen: addedSpecimen) mapView.addAnnotation(annotation) lastAnnotation = nil; >
Этот метод вызывается тогда, когда вы только вернулись из AddNewEntryController и у вас есть новые образцы, которые нужно добавить на карту. При добавлении нового образца на карту, он получает шаблонную аннотационную иконку. Теперь, когда у вас есть категория, вы хотите заменить эту иконку на иконку конкретной категории. Вы просто удаляете последнюю аннотацию, добавленную на карту и заменяете ее на аннотацию, которая показывает имя и категорию вида.
Запустите приложение, создайте новые образцы различных категорий и посмотрите, как происходит обновление карт:

Другой ракурс
Вы, возможно, заметили кнопку Log в верхнем левом углу карты. В дополнение к карте, приложение также имеет table view в виде текстового списка всех аннотаций под названием Log View. Теперь вы будете заполнять этот table view данными.
Откройте LogViewController.swift и импортируйте снова RealmSwift ниже других выражений import:
import RealmSwift
Затем замените свойство specimens на следующее:
var specimens = try! Realm().objects(Specimen).sorted("name", ascending: true)
В приведенном выше коде, вы заменяете массив плейсхолдеров массивом Results, которые держат Specimen-ы так же, как вы это делали в MapViewController. Они будут отсортированы по name.
Затем замените tableView(_:cellForRowAtIndexPath:) следующей реализацией:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell < let cell = self.tableView.dequeueReusableCellWithIdentifier("LogCell") as! LogCell let specimen = specimens[indexPath.row] cell.titleLabel.text = specimen.name cell.subtitleLabel.text = specimen.category.name switch specimen.category.name < case "Uncategorized": cell.iconImageView.image = UIImage(named: "IconUncategorized") case "Reptiles": cell.iconImageView.image = UIImage(named: "IconReptile") case "Flora": cell.iconImageView.image = UIImage(named: "IconFlora") case "Birds": cell.iconImageView.image = UIImage(named: "IconBird") case "Arachnid": cell.iconImageView.image = UIImage(named: "IconArachnid") case "Mammals": cell.iconImageView.image = UIImage(named: "IconMammal") default: cell.iconImageView.image = UIImage(named: "IconUncategorized") >return cell >
Этот метод теперь будет заполнять ячейку с именем образца и категорию.
Запустите приложение. Нажмите Log и вы увидите все ваши введенные образцы в table view, вот как:

Получение с применением предикатов
Если вы действительно хотите, чтобы ваше приложение преуспело, вам понадобится удобная функция поиска. Ваш стартовый проект содержит экземпляр UISearchController - вам нужно просто добавить несколько модификаций, подходящих для вашего приложения, чтобы заставить его работать с Realm.
В LogViewController.swift замените свойство searchResults следующим текстом:
var searchResults = try! Realm().objects(Specimen)
Теперь добавьте метод классу ниже:
func filterResultsWithSearchString(searchString: String) < let predicate = NSPredicate(format: "name BEGINSWITH [c]%@", searchString) // 1 let scopeIndex = searchController.searchBar.selectedScopeButtonIndex // 2 let realm = try! Realm() switch scopeIndex < case 0: searchResults = realm.objects(Specimen).filter(predicate).sorted("name", ascending: true) // 3 case 1: searchResults = realm.objects(Specimen).filter(predicate).sorted("created", ascending: true) // 4 default: searchResults = realm.objects(Specimen).filter(predicate) // 5 >>
Вот для чего нужна данная функция:
- Сначала необходимо создать предикат, который осуществляет поиск name (имен), которые начинаются с searchString. [c], следующая за BEGINSWITH, указывает на поиск без учета регистра.
- Затем вы берете ссылку на индекс выделенной области видимости из поисковой строки.
- Если выбрана первая кнопка на segmened control, то результаты будут отсортированы по названию в возрастающем порядке.
- Если выбрана вторая кнопка, отсортируйте результаты по дате создания по возрастанию.
- Если ни одна из кнопок не выбрана, то результаты сортироваться не будут, мы просто будем брать их в том порядке, в каком они вернулись из базы данных.
Теперь вам на самом деле нужно выполнить сортировку в момент, когда пользователь взаимодействует с полем поиска. В updateSearchResultsForSearchController(_:) добавьте следующие две строчки в начале метода:
let searchString = searchController.searchBar.text! filterResultsWithSearchString(searchString)
Так как table view c результатами поиска вызывает те же методы, вам потребуется небольшое изменение в tableView(_:cellForRowAtIndexPath:) для обработки основного log table view и результатов поиска. В этом методе, найдите строку, которая присваивает значение в specimen:
let specimen = specimens[indexPath.row]
Удалите эту строку и замените ее следующей:
let specimen = searchController.active ? searchResults[indexPath.row] : specimens[indexPath.row]
Код выше проверяет, активен ли searchController, если да, то он извлекает образец из searchResults, если нет, то он вместо этого извлекает образец из specimens.
Наконец, вам нужно добавить функцию для сортировки возвращаемых результатов, когда пользователь нажимает кнопку в панели области действия.
Замените пустой scopeChanged(_:) следующим кодом:
@IBAction func scopeChanged(sender: AnyObject) < let scopeBar = sender as! UISegmentedControl let realm = try! Realm() switch scopeBar.selectedSegmentIndex < case 0: specimens = realm.objects(Specimen).sorted("name", ascending: true) case 1: specimens = realm.objects(Specimen).sorted("created", ascending: true) default: specimens = realm.objects(Specimen).sorted("name", ascending: true) >tableView.reloadData() >
В коде выше вы проверяете, какая scope кнопка нажата - A-Z, или Date Added - и вызываете соответственно arraySortedByProperty(_:ascending:). По умолчанию список будет сортироваться по name.
Запустите приложение; задайте несколько различных поисков и посмотрите, что вы получите в результате!

Обновление записей
Вы разобрали добавление записей, но как их обновлять?
Если вы кликните в ячейке LogViewController, то перейдете непосредственно к AddNewEntryViewController, но поля будут пустыми. Конечно, первый шаг - это позволить пользователю редактировать поля для отображения существующих данных!
Откройте AddNewEntryViewController.swift и добавьте следующий вспомогательный метод классу:
func fillTextFields()
Этот метод в пользовательском интерфейсе заполнит данные образца. Помните, что AddNewEntryViewController до этого момента использовался только для новых образцов, так что эти поля всегда изначально были пустыми.
Добавьте следующие строки в конце viewDidLoad():
if let specimen = specimen < title = "Edit \(specimen.name)" fillTextFields() >else
Приведенный выше код устанавливает заголовок панели навигации для того, чтобы сказать, добавляет ли пользователь новый экземпляр или обновляет уже существующий. Если это уже существующий образец, вы можете также вызвать вспомогательный метод для заполнения полей.
Теперь вам нужен способ для обновления записи образца с изменениями пользователя. Добавьте следующий метод классу:
func updateSpecimen() < let realm = try! Realm() try! realm.write < self.specimen.name = self.nameTextField.text! self.specimen.category = self.selectedCategory self.specimen.specimenDescription = self.descriptionTextField.text >>
Как обычно, метод начинается с получения экземпляра Realm, а затем остальное оборачивается внутрь транзакции write(). Внутри транзакции, вы просто обновляете три поля данных.
Все, что вам нужно для обновления Specimen - это шесть строчек кода! :]
Теперь вам нужно вызвать описанный выше метод, когда пользователь нажимает Confirm. Найдите shouldPerformSegueWithIdentifier(_:sender:) и замените его следующим образом:
override func shouldPerformSegueWithIdentifier(identifier: String?, sender: AnyObject?) -> Bool < if validateFields() < if specimen != nil < updateSpecimen() >else < addNewSpecimen() >return true > else < return false >>
Это вызовет вспомогательный метод для обновления данных в случае необходимости.
Теперь откройте LogViewController.swift и добавьте следующую реализацию для prepareForSegue(_:sender:):
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) < if (segue.identifier == "Edit") < let controller = segue.destinationViewController as! AddNewEntryController var selectedSpecimen: Specimen! let indexPath = tableView.indexPathForSelectedRow if searchController.active < let searchResultsController = searchController.searchResultsController as! UITableViewController let indexPathSearch = searchResultsController.tableView.indexPathForSelectedRow selectedSpecimen = searchResults[indexPathSearch!.row] >else < selectedSpecimen = specimens[indexPath!.row] >controller.specimen = selectedSpecimen > >
Вам нужно передать выбранный образец экземпляру AddNewEntryController. Сложность произвести это с if / else заключается в том, что получение выбранного образца немного отличается, в зависимости от того, смотрит пользователь на результаты поиска или нет.
Запустите приложение, откройте окно Log и нажмите на существующий Specimen. Вы должны увидеть детали, заполненные поля, готовые к редактированию.

Что дальше?
Дальше, вы можете продолжить изучать наши туториалы по мере их появления, а также, параллельно читать перевод официальной книги по языку программирования Swift. И, для более подробного изучения языка, вы можете пройти наши курсы!
Урок подготовил: Акулов Иван