Книга: Swift. Основы разработки приложений под iOS, iPadOS и macOS. 5-е изд. дополненное и переработанное
Назад: Часть VII. Введение в мобильную разработку
Дальше: 39. Паттерны проектирования при разработке в Xcode

38. Разработка приложения под iOS

Очень важно, чтобы вы погружались в разработку плавно, без рывков в изучении материала. Мы будем максимально подробно разбирать каждый шаг, останавливаясь на новых и пока еще неизвестных понятиях и механизмах Xcode.  

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

38.1. Создание проекта MyName

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

Задание

Создайте новый проект для платформы iOS типа Single View Application с именем MyName.

Прежде чем приступить к разработке приложения, обратимся к редактору проекта. Сейчас в нем отображаются настройки вашего приложения (рис. 38.1).

Напомню, что изменение настроек проекта доступно в том случае, когда в Project Navigator выбран корневой объект дерева ресурсов (в данном случае это MyName).

В верхней части рабочей области расположена панель вкладок, с помощью которой можно перемещатьcя между различными группами настроек. В настоящий момент активна вкладка General, и именно ее состав отображается в редакторе проекта. С ее помощью вы можете

Рис. 38.1. Настройки проекта MyName

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

Все параметры вкладки General разделены на разделы. Раздел Identify содержит следующие параметры:

• Display Name — имя проекта, которое вы задавали при его создании. Значение данного поля не подлежит редактированию.

• Bundle Identify — идентификатор продукта.

• Version — версия приложения.

• Build — номер сборки приложения.

Прежде чем вы разместите свое новое приложение в магазине AppStore, его необходимо подписать с помощью цифровой подписи. Возможность (или невозможность) совершения этой операции указана в разделе Signing. Обратите внимание на раздел Deployment Info. В нем содержатся параметры, непосредственно влияющие на работу приложения. Так, например, параметр Devices определяет устройства, под которыми будет работать ваше приложение. Значение Universal говорит о том, что ваше приложение будет работать как под iPhone, так и под iPad. Щелкните по выпадающему списку и выберите iPhone.

38.2. Interface Builder, Storyboard и View Controller

Пришло время перейти к разработке пользовательского интерфейса (User Interface, сокращенно UI) вашего приложения.

Взгляните на Project Navigator: там появилось множество новых, по сравнению с проектом консольного приложения, ресурсов (рис. 38.2).

Рис. 38.2. Структура проекта MyName

ПРИМЕЧАНИЕ Обратите внимание, что в случае, если при создании проекта вы не сняли галочки с пунктов Include Unit Tests и Include UI Tests, в структуре проекта будут расположены папки MyNameTests и MyNameUITests.

Рассмотрение их содержимого и возможностей тестирования приложений выходит за рамки темы данной книги.

Файлы с расширением swift (AppDelegate.swift и ViewController.swift) содержат исходный код приложения. Файлы с расширением storyboard (Main.storyboard и LaunchScreen.storyboard) ранее нам не встречались. Они предназначены для создания UI приложения, и этот процесс в Xcode очень прост и понятен, с ним мы вскоре познакомимся. Щелкните по файлу Main.storyboard в области навигации и обратите внимание на то, как изменился Project Editor (рис. 38.3). Перед вами открылся редактор интерфейса (Interface Builder, сокращенно IB).

Interface Builder обеспечивает удобный визуальный способ создания и редактирования UI приложений. С помощью IB создается рас­кадровка (storyboard), состоящая из одного или нескольких рабочих

Рис. 38.3. Редактор интерфейса

экранов и набора связей между этими экранами. Каждый отдельный рабочий экран вашего приложения называется сценой (scene). С помощью редактора интерфейса вы можете создать необходимое количество сцен и обеспечить их взаимодействие между собой. И все это может быть сделано без единой строчки кода!

Сейчас storyboard вашего приложения состоит всего из одной сцены.

ПРИМЕЧАНИЕ Во время своей работы Interface Builder взаимодействует с файлами xib (они не отображаются в Project Navigator, вы можете увидеть их лишь в файловой системе, в папке с проектом). Это обычные текстовые файлы, имеющие XML-формат и описывающие графические элементы интерфейса. Storyboard-файлы, в свою очередь, компонуют множество xib-файлов. Читая документацию или статьи о разработке в Xcode, вы можете встретить упоминания nib-файлов. В настоящее время nib-формат является устаревшим, ему на смену пришел xib, но в силу исторических причин такие файлы порой все еще называются nib.

Обратите внимание на Jump Bar (панель перехода), расположенную прямо над Interface Builder (рис. 38.4). Это очень полезный функ­циональный элемент Xcode, с его помощью, так же как и в Project Navigator, вы можете выбирать ресурс, который требуется отобразить в редакторе проекта. В дальнейшем вы будете очень часто его использовать.

Рис. 38.4. Jump Bar, предназначенный для перехода между ресурсами проекта

Ранее на этапе создания проекта в качестве шаблона был выбран Single View Application, что дословно переводится как «приложение с одним отображением». В соответствии с этим шаблоном файл Main.storyboard содержит одну сцену, то есть один рабочий экран приложения (вернитесь к рис. 38.3). Со временем storyboard вашего приложения может обзавестись большим количеством сцен. Пример storyboard с большим количеством сцен приведен на рис. 38.5.

Рис. 38.5. Storyboard с большим количеством сцен

Как говорилось ранее, в состав storyboard любого приложения входят:

• одна или несколько сцен;

• связи между сценами.

При этом в любой сцене можно выделить следующие элементы:

• отображения (views, среди программистов также называемые «вьюшками») графических элементов сцены (кнопок, надписей, таблиц и т.д.);

• дополнительные элементы, обеспечивающие функциональность сцены.

Отображения могут входить в состав друг друга. Они являются базовыми строительными блоками, из которых и создается UI приложение.

ПРИМЕЧАНИЕ Вы наверняка помните, как использовали вложенные друг в друга отображения при разработке приложения, позволяющего двигать шарики в Xcode Playground.

В левой части Interface Builder находится Document outline (схема документа) (рис. 38.6). Если отобразить все вложенные в View Controller Scene элементы, то вы увидите полную структуру вашего storyboard. Если Project Navigator позволяет вам получить доступ к различным ресурсам проекта, в том числе к storyboard-файлам, то благодаря Document outline вы получаете очень удобный способ доступа к элементам, входящим в состав storyboard.

Рис. 38.6. Структура storyboard

Пока что storyboard состоит всего из одной сцены, которые называются View Controller Scene в Document outline. Он, в свою очередь, состоит из следующих элементов:

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

• View определяет непосредственно саму сцену, а точнее, экземпляр класса UIView, который является визуальным макетом, загружаемым и отображаемым средствами View Controller на экран вашего устройства. View — это иерархическая структура, а значит, отображения различных графических элементов могут создавать дерево и входить в состав друг друга. Ранее вы встречались с классом UIView при создании интерактивного Xcode Playground. Если вы щелкнете по иконке View в Document Outline, то Xcode автоматически подсветит квадрат, соответствующий экрану на вашей сцене в storyboard.

• Safe Area описывает сцену приложения, исключая верхний бар с данными о сотовой сети, заряде батареи и другой системной информацией.

• First Responder всегда указывает на объект, с которым пользователь взаимодействует в данный момент. При работе с iOS-при­ложениями пользователь потенциально может начать взаимодействие со многими элементами, расположенными на сцене. Например, если он начал вводить данные в текстовое поле (tetxfield), то именно оно и будет являться first responder в данный момент.

• Exit служит единственной специфической цели и используется только в приложениях с множеством сцен. Когда вы создаете программу, которая перемещает пользователя между набором экранов, то exit обеспечивает перемещение к одному из предыдущих экранов.

• Storyboard Entry Point является указателем на то, какая именно сцена будет отображена при запуске приложения.

ПРИМЕЧАНИЕ Не переживайте, если предназначение каких-либо (или всех) элементов вам не в полной мере понятно. Со временем вы поработаете с каждым из них.

ПРИМЕЧАНИЕ Стоит отметить, что указанная иерархия сцены является условной: например, элементы Storyboard Entry Point и Exit описывают связи сцен, а ранее мы говорили о том, что связи являются составной частью storyboard, но не сцены. Похожая ситуация и с View Controller: по сути, он не входит в состав сцены — он обеспечивает ее работу.

В Xcode 9 был добавлен новый элемент Safe Area. Его появление связано с выходом iPhone X (и его экраном необычной формы) и появившимся в связи с этим новым подходом к работе со сценами. В правой панели откройте File inspector и взгляните в раздел Interface Builder Document (рис. 38.7). В нем расположен переключатель Use Safe Area Layout Guides, с помощью которого можно выбрать вариант работы со сценой (использовать Safe zone или старый вариант).

Рис. 38.7. Переключатель Use Safe Area Layout Guides

Уберите галочку переключателя и обратите внимание на изменения в Document outline. Из View Controller исчез Safe zone, но появились два новых элемента:

• Top Layout Guide описывает «шапку» вашего приложения, обычно расположенную сразу под статусбаром с часами (рис. 38.8).

Рис. 38.8. Пример «шапки» приложения

• Bottom Layout Guide описывает «подвал» вашего приложения, обычно расположенный в самом низу сцены (рис. 38.9).

Рис. 38.9. Пример «подвала» приложения

В следующей версии Xcode данный функционал, вероятно, будет полностью удален. В связи с этим поставим галочку напротив Use Safe Area Layout Guides и в дальнейшем будем работать именно с Safe zone.

Одним из пунктов в схеме документа является View Controller (контроллер отображения). Запомните, данный контроллер в действительности не входит в состав сцены, он лишь обеспечивает ее отображение. View Controller — это внешний объект, предназначенный для управления ассоциированной с ним сценой и набором отображений, входящих в эту сцену.

ПРИМЕЧАНИЕ Чуть позже мы подробнее разберем, что такое View Controller и как организуется его взаимосвязь с отображениями.

Некоторые элементы на панели структуры сцены имеют соответствующие им графические элементы на самой сцене (рис. 38.10). Пощелкайте по всем элементам в Document outline и посмотрите, что будет подсвечиваться на изображении сцены справа.

Рис. 38.10. Соответствие элементов схемы элементам сцены

ПРИМЕЧАНИЕ Если в верхней части вашей сцены вместо трех значков отображается надпись View Controller, то для их отображения достаточно щелкнуть по любому элементу на панели структуры сцены.

38.3. Разработка простейшего UI

Убедитесь, что в Project Navigator файл Main.storyboard является активным, а в редакторе проекта отображается Interface Builder.

При разработке графических приложений Xcode позволяет использовать шаблоны визуальных элементов, таких как текстовое поле, надпись, ползунок, кнопка и многие другие, которые могут быть полезны во время разработки графического интерфейса приложений. Для доступа к библиотеке объектов нажмите кнопку Library (), расположенную в Toolbar, после чего перед вами появятся все доступные элементы (рис. 38.11).

Рис. 38.11. Библиотека объектов

С помощью кнопки Switch to в правом верхнем углу библиотеки объектов вы можете выбрать вид отображения объектов в виде списка или сетки.

ПРИМЕЧАНИЕ Все объекты доступны благодаря фреймворку UIKit, в состав которого они входят.

Перейдем непосредственно к использованию IB и разработке UI приложения. Следующим шагом станет размещение на сцене кнопки. Для этого в библиотеке объектов найдите элемент Button (можете использовать поле поиска, введя в него имя искомого элемента) и перетащите его в IB, прямо в центр вашей сцены. После размещения объекта он появится на панели структуры сцены в разделе Views (рис. 38.12). Теперь View сцены (экземпляр класса UIView) содержит вложенный View кнопки, который является экземпляром класса UIButton.

Рис. 38.12. Размещение элемента Button на сцене

ПРИМЕЧАНИЕ Обратите внимание, что при размещении объекта в центре сцены начинают отображаться вспомогательные прерывистые линии синего цвета. С их помощью вы можете эффективно размещать графические элементы на сцене.

Теперь изменим текст кнопки. Для его изменения дважды щелкните по ней и введите «Hello World». После этого для сохранения изменений нажмите Enter на клавиатуре.

ПРИМЕЧАНИЕ После изменения текста вам может потребоваться повторная отцентровка кнопки на сцене.

38.4. Запуск приложения в эмуляторе

Разработка iOS-проектов была бы чрезвычайно сложной в том случае, если бы в целях тестирования их требовалось запускать только на реальном устройстве. С целью оптимизации этого процесса в состав Xcode включены эмуляторы всех имеющихся на данный момент на рынке устройств «яблочной» корпорации. Таким образом, разрабатываемое вами приложение MyName при запуске, если не указано иное, будет отображаться в окне эмулятора iPhone.

С тем, как производить запуск приложения, вы познакомились при создании консольного приложения. В текущем проекте панель инструментов также содержит набор кнопок для запуска процесса сборки и осуществления принудительной остановки запущенного приложения. Дополнительно имеется возможность выбрать устройство, на эмуляторе которого будет запущен проект (рис. 38.13). Вопрос тестирования приложений на различных эмуляторах становится очень актуальным в связи с тем, что сегодня iOS функционирует на большом числе устройств с большим количеством разрешений.

Рис. 38.13. Кнопки запуска проекта

ПРИМЕЧАНИЕ Xcode позволяет также разрабатывать приложения, которые будут работать одновременно на разных устройствах, в том числе с различным соотношением сторон и разрешением экрана.

Запустите приложение с помощью кнопки Build and run на панели инструментов.

В статус-баре виден текущий статус проекта. После запуска сборки проекта информация, отображаемая в нем, позволяет определить, на каком этапе работы находится ваш проект (рис. 38.14).

Рис. 38.14. Изменения в статусбаре во время запуска проекта

Рис. 38.15. Окно эмулятора

В результате ваше iOS-приложение отобразится в окне эмулятора (рис. 38.15), в центре которого будет расположена кнопка с текстом «Hello World». Попробуйте щелкнуть на ней. При этом ничего не происходит, так как пока мы не запрограммировали какие-либо дальнейшие действия.

Теперь остановите запущенное приложение с помощью кнопки Stop the running scheme or application и на панели инструментов щелкните на ­названии модели iPhone, на котором производилась эмуляция (вероятно, был выбран iPhone Xr). В выпадающем списке выберите iPhone 8 Plus и произведите повторный запуск проекта.

На этот раз кнопка «Hello World» будет расположена не в центре, а немного ниже от него! И это на первый взгляд удивительно. Чтобы понять, в чем проблема, вернитесь в Xcode. В нижней части редактора проекта указано, что IB должен отображать экран, соответствующий iPhone Xr, но при этом программа запускалась на эмуляторе iPhone 8 Plus (рис. 38.16). Эти устройства имеют различные разрешения, а в связи с тем, что координаты кнопки фиксируются в пикселах по отступу от левого верхнего угла, на разных устройствах кнопка располагается в разных местах.

Рис. 38.16. Различные типы устройств

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

38.5. View Controller сцены и класс UIViewController

На этом этапе мы добавим нашей кнопке функциональные возможности. В Project Navigator щелкните по файлу ViewController.swift, после чего его содержимое отобразится в Project Editor. Как вы видите, в коде файла уже присутствует класс ViewController (листинг 38.1). Это связано с тем, что в качестве шаблона приложения был выбран Single View Application.

Листинг 38.1

class ViewController: UIViewController {

    override func viewDidLoad() {

        super.viewDidLoad()

        // Do any additional setup after loading the view.

    }

}

Xcode позволяет создать связь и организовать взаимодействие кода и элементов интерфейса. Для этого нужно связать объект View Controller, отображенный в Document outline и входящий в состав сцены, и класс ViewController, описанный в файле ViewController.swift. Это позволит влиять на элементы интерфейса с помощью программного кода.

Шаблон Single View Application, который был выбран при создании проекта, изначально содержит одну сцену со своим View Controller, один класс ViewController и уже настроенную связь между ними. Схематично эта связь приведена на рис. 38.17.

Рис. 38.17. Связь объекта View Controller и класса ViewController

Работая над сложными проектами, вы будете создавать большое количество различных сцен (а значит, и элементов View Controller), классов и связей между ними. Для этой цели в Xcode есть возможность настройки и изменения уже созданных связей между View Controller и классами. Для этого в Project Navigator выберите файл Main.storyboard, после чего в Document Outline выделите элемент View Controller. Далее, в Utilities Area откройте вкладку Identify Inspector, нажав кнопку Show the Identify Inspector ().

Параметр Class в разделе Custom Class содержит ссылку на связанный со сценой программный класс, в данном случае это ViewController (рис. 38.18).

Рис. 38.18. Отображение связи элемента сцены View Controller и класса ViewController

Вернемся к классу ViewController в файле ViewController.swift. Обратите внимание на два важных момента.

В самом начале подключается фреймворк UIKit (листинг 38.2).

Листинг 38.2

import UIKit

Класс ViewController является подклассом UIViewController (лис­тинг 38.3).

Листинг 38.3

class ViewController: UIViewController {…}

ПРИМЕЧАНИЕ Напомню, что два класса могут находиться в отношении «суперкласс — подкласс (субкласс)». Подкласс наследует все характеристики (свойства и методы) родительского класса. Имя суперкласса (если он имеется) указывается при определении подкласса через двоеточие.

С библиотекой UIKit мы встречались уже не один раз. Напомню, что UIKit — это фреймворк, входящий в стандартную поставку Xcode. Он обеспечивает функциональные возможности для построения и управления пользовательским интерфейсом, анимацией, текстом, изображениями для ваших приложений, а также для обработки событий, происходящих во время работы пользователя. Если говорить проще, то UIKit — это набор основных возможностей, которые разработчики используют при построении интерфейса практически любого приложения.

В библиотеке UIKit описан класс UIViewController, предназначенный для описания инфраструктуры и управления отображениями приложения. Основной функцией UIViewController (а также его потомков) является обновление содержимого отображений, в том числе в ответ на действия пользователей.

ПРИМЕЧАНИЕ В дальнейшем вы практически не будете создавать экземпляры класса UIViewController, наиболее часто используемым решением будет, как и в нашем случае, создание потомков UIViewController с целью расширения его возможностей собственным функционалом.

Обратите внимание на метод viewDidLoad(), описанный в классе ViewController. Так как вы создали приложение, используя шаблон Single View Application, Xcode автоматически переопределил его в коде класса ViewController. Родительский класс UIViewController имеет большое количество методов, которые могут быть переопределены в потомках. Каждый из этих методов служит для решения конкретной задачи (например, выполнение блока кода сразу после вывода отображения на экран устройства). Со многими из таких методов вы познакомитесь в процессе изучения вопроса разработки приложений в Xcode.

Несмотря на то что viewDidLoad() не содержит какого-либо кода, а лишь вызывает одноименный родительский метод, при необходимости он может быть расширен для реализации требуемого функционала. Но в некоторых случаях в его использовании нет необходимости, а значит, его можно удалить. О том, для чего предназначен viewDidLoad(), мы поговорим позже. Сейчас вам требуется убрать его из класса ViewController (листинг 38.4).

Листинг 38.4

class ViewController: UIViewController {

}

38.6. Доступ UI к коду. Определитель типа @IBAction

Добавим в наше приложение простейшие функциональные возможности, а именно вывод на консоль текстового сообщения при нажатии на кнопку. Ранее мы говорили, что класс ViewController ассоциирован с элементом View Controller сцены. Соответственно, для создания дополнительного функционала необходимо работать именно с этим классом. Расширим его новым методом showMessage(), использующим внутри своей реализации функцию print(_:) с текстом "you press Hello World button" (листинг 38.5).

ПРИМЕЧАНИЕ Не забывайте, что вы можете использовать кодовые сниппеты для упрощения создания кодовых конструкций.

Листинг 38.5

class ViewController: UIViewController {

     func showMessage(){

          print("you press Hello World button")

     }

}

Для того чтобы появилась возможность создать связь между методом класса и элементом сцены, используется определитель типа @IBAction (среди разработчиков называемый «экшеном»), указываемый перед определением метода. Добавим @IBAction к методу showMessage() (лис­тинг 38.6).

Листинг 38.6

class ViewController: UIViewController {

    @IBAction func showMessage(){

         print("you press Hello World button")

    }

}

ПРИМЕЧАНИЕ Обратите внимание, что слева от метода showMessage() вместо номера строки теперь отображается серый квадрат.

Ключевое слово @IBAction разрешает графическим элементам в Interface Builder осуществлять доступ к методам класса.

ПРИМЕЧАНИЕ Для создания обратной связи, когда метод обращается к элементам интерфейса, необходимо использовать определитель @IBOutlet. С ним мы познакомимся позже.

Так как метод showMessage() помечен с помощью экшена, мы можем организовать его вызов по событию «нажатие на кнопку». Для этого в IB откройте Main.storyboard, зажмите Control на клавиатуре и с помощью мышки потяните кнопку «Hello World» на желтый круглый символ View Controller (рис. 38.19), после чего отпустите. В процессе перетаскивания от кнопки к указателю мышки будет идти линия синего цвета.

Рис. 38.19. Создание связи между View Controller и showMessage()

В появившемся окне выберите элемент showMessage, находящийся в разделе Sent Events (рис. 38.20).

ПРИМЕЧАНИЕ Метод showMessage() доступен для связывания и находится в выпадающем списке, так как помечен ключевым словом @IBAction.

Рис. 38.20. Выбор showMessage() для связи с кнопкой на сцене

Теперь, если запустить приложение и щелкнуть на кнопке, то будет вызван метод showMessage() класса ViewController, а значит, произойдет вывод фразы "you press Hello World button" на консоль (рис. 38.21).

Рис. 38.21. Вывод на консоль по нажатии кнопки на сцене

ПРИМЕЧАНИЕ Обратите внимание, что на рис. 38.21 приложение снова запущено на эмуляторе iPhone Xr.

38.7. Отображение всплывающего окна. Класс UIAlertController

Следующим шагом станет реализация появления всплывающего окна при нажатии на кнопку на сцене. Для этого также будем использовать метод showMessage().

В Xcode для работы со всплывающими окнами (оповещениями) используется класс UIAlertController. Оповещение может быть отображено в классическом виде в центре экрана (тип Alert) (рис. 38.22) или в нижней части сцены (тип Action Sheet) (рис. 38.23).

Рис. 38.22. UIAlertController в виде Alert

Рис. 38.23. UIAlertController в виде Action Sheet

Рассмотрим использование UIAlertController подробнее.

Синтаксис

Класс UIAlertController

Предназначен для создания всплывающего окна. Является потомком класса UIViewController.

Инициализаторы:

init( title: String?, message: String?, preferedStyle: UIAlertControllerStyle).

Доступные свойства и методы:

var title: String? — заголовок окна.

var message: String? — текст, выводимый ниже заголовка.

var preferedStyle: UIAlertControllerStyle — стиль всплывающего окна.

func addAction( UIAlertAction ) — создание кнопки на всплывающем окне.

Пример

let alertController = UIAlertController(title: "Alert", message: "Text of alert", preferredStyle: UIAlertControllerStyle.alert).

Аргумент preferedStyle инициализатора класса, имеющий тип UIAlert­Controller.Style, определяет стиль всплывающего окна. Именно значение данного параметра указывает на то, оповещение какого типа будет создано: Alert или Action Sheet.

Синтаксис

Перечисление UIAlertController.Style

Определяет тип всплывающего окна. Входит в состав типа UIAlertController.

Доступные свойства:

alert — всплывающее окно типа Alert.

actionSheet — всплывающее окно типа Action Sheet.

Пример

UIAlertController.Style.actionSheet

Реализуем всплывающее окно в коде нашего приложения. В методе showMessage() создадим экземпляр класса UIAlertController и запишем его в константу alertController (листинг 38.7).

Листинг 38.7

@IBAction func showMessage(){

     let alertController = UIAlertController(

        title: "Welcome to MyName App",

        message: "Vasiliy Usov",

        preferredStyle: UIAlertController.Style.alert)

}

Данные, хранящиеся в alertController, являются не чем иным, как экземпляром класса UIAlertController. При выполнении метода showMessage() всплывающее окно не отобразится. Для того чтобы графический элемент был показан поверх сцены, используется метод present(_:animated:competition), входящий в состав класса UIViewController. Он должен быть применен не к всплывающему окну, а к самому отображению сцены, а экземпляр класса UIAlertController передается ему в качестве аргумента.

Синтаксис

Метод UIViewController.present(_:animated:competition)

Предназначен для показа отображения графического элемента поверх экземпляра класса UIViewController в виде модального окна. Данный метод должен быть вызван после внесения всех изменений в выводимое отображение.

Аргументы:

_: UIViewController — отображение, которое будет показано на экране устройства.

animated: Bool — флаг, указывающий на необходимость использования анимации при отображении элемента.

competition: (() -> Void)? = nil — замыкание, исполняемое после завершения показа элемента.

Пример

self.present(alertController, animated: true, completion: nil)

Добавим вывод всплывающего окна с помощью метода present(_:ani-mated:competition) (листинг 38.8).

Листинг 38.8

@IBAction func showMessage(){

    let alertController = UIAlertController(

        title: "Welcome to MyName App",

        message: "Vasiliy Usov",

        preferredStyle: UIAlertController.Style.alert)

    // вывод всплывающего окна

    self.present(alertController, animated: true, completion: nil)

}

Запустите программу и щелкните на кнопке «Hello World». При этом будет произведен вывод оповещения (рис. 38.24).

Добавим к всплывающему окну пару кнопок. Для этого используется метод addAction(_:) класса UIAlertController.

Синтаксис

Метод UIAlertController.addAction(_:)

Предназначен для добавления во всплывающее окно функциональных элементов (кнопок).

Аргументы:

_: UIAlertAction — экземпляр, описывающий функциональный элемент.

Пример:

alertController.addAction(

  UIAlertAction(

    title: "OK",

    style: UIAlertAction.Style.default,

    handler: nil))

Рис. 38.24. UIAlertController типа Alert без функциональных кнопок

Аргумент типа UIAlertAction в методе addAction(_:) определяет и описывает функциональную кнопку.

Синтаксис

Класс UIAlertAction

Создает функциональную кнопку и определяет ее текст, стиль и реакцию на нажатие.

Инициализаторы:

init(title: String?, style: UIAlertActionStyle, handler: ((UIAlertAction) -> Void)? = nil)

Доступные свойства и методы:

var title: String? — текст, расположенный на кнопке.

var style: UIAlertActionStyle — стиль кнопки.

var handler: ((UIAlertAction) -> Void)? = nil — обработчик нажатия кнопки.

Пример

UIAlertAction(

  title: «Text of title»,

  style: UIAlertAction.Style.default,

  handler: nil)

Аргумент style инициализатора класса имеет тип данных UIAlertAction.Style и определяет внешний вид (стиль) кнопки.

Синтаксис

Перечисление UIAlertAction.Style

Определяет внешний вид функционального элемента (кнопки) во всплывающем окне. Входит в состав типа UIAlertAction.

Доступные свойства:

Default — текст кнопки написан без выделения.

Cancel — текст кнопки написан жирным.

Destructive — текст кнопки написан красным.

Пример

UIAlertAction.Style.cancel

Мы рассмотрели все типы данных, методы и свойства, участвующие в процессе создания и отображения всплывающего окна. Добавим с помощью метода addAction(_:) (листинг 38.9) две кнопки в оповещение.

ПРИМЕЧАНИЕ Не забывайте, что все изменения с элементом, в том числе и создание кнопок, должны быть произведены до его вывода с помощью метода present(_:animated:competition).

Листинг 38.9

@IBAction func showMessage(){

    let alertController = UIAlertController(

    title: "Welcome to MyName App",

    message: "Vasiliy Usov",

    preferredStyle: UIAlertController.Style.alert)

    // добавляем кнопки к всплывающему сообщению

    alertController.addAction(UIAlertAction(title: "First", style: UIAlertAction.Style.default, handler: nil))

    alertController.addAction(UIAlertAction(title: "Second", style: UIAlertAction.Style.default, handler: nil))

    // вывод всплывающего окна

    self.present(alertController, animated: true, completion: nil)

}

Теперь вы можете запустить приложение в эмуляторе и наслаждаться его работой. Модальное окно будет отображаться при нажатии кнопки на сцене и закрываться после нажатия любой из его кнопок (рис. 38.25).

Рис. 38.25. Вывод модального окна с двумя кнопками

Все методы, имеющие связь с каким-либо графическим элементом в редакторе кода, отмечаются с помощью серого кружка вместо номера строки (рис. 38.26). Нажав на него, вы сможете осуществить переход в IB к элементу сцены.

Рис. 38.26. Указатель на связь кодовой конструкции и графического элемента

38.8. Изменение атрибутов кнопки

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

Для доступа к атрибутам, а также их редактирования служит Attribute Inspector (Инспектор атрибутов), который можно отобразить с помощью кнопки Show the Attribute Inspector , расположенной в верхней части Utilities Area (рис. 38.27).

С помощью Attribute Inspector можно изменить некоторые свойства кнопки:

• Цвет текста кнопки — на красный.

• Стиль текста — на жирный.

• Размер текста — на значение «20».

Для этого в IB выделите кнопку на сцене и включите Панель атрибутов. За цвет текста отвечает атрибут Text Color, находящийся в разделе Button. Вы можете изменить его значение на любой другой цвет, щелкнув по синему прямоугольнику и выбрав Custom в появившемся списке, после чего отобразится всплывающее окно с палитрой доступных цветов (рис. 38.28). Выберите в палитре красный цвет, после чего закройте окно палитры.

Рис. 38.27. Инспектор атрибутов элемента «Кнопка»

Рис. 38.28. Смена цвета текста кнопки

Настройки шрифта определены в атрибуте Font. Если нажать на иконку с буквой T, то в появившемся окне вы сможете изменить шрифт, стиль его начертания и размер (рис. 38.29). Для установки жирного шрифта выберите Bold в качестве значения параметра Style. Размер текста можно изменить в поле Size: установите его равным 20.

Теперь кнопка в вашей программе выглядит иначе (рис. 38.30), при этом ее функциональность совершенно не изменилась — она по-прежнему вызывает всплывающее окно.

Рис. 38.29. Смена настроек шрифта текста кнопки

ПРИМЕЧАНИЕ Возможно, что после проведения настроек текст на вашей кнопке перестал в нее помещаться, а вместо некоторых букв появились точки. Чтобы это исправить, просто выделите кнопку в IB и растяните нужным вам образом, потянув за уголок или грань.

Рис. 38.30. Измененная кнопка в приложении

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

Задание

Сейчас вам потребуется создать на сцене несколько новых элементов. Разместите две кнопки (элемент Button) и надпись/метку (элемент Label в библиотеке объектов) так, как показано на рис. 38.31. Кнопки должны иметь текст «Left» и «Right», а метка — «Press some button». Элементы расположите в одну строку.

Рис. 38.31. Новые элементы на форме

Подсказка 1

Для поиска элементов в Object Library вы можете использовать поле Filter, вводя в него Button и Label. После этого достаточно просто перетащить нужные элементы на сцену.

Подсказка 2

Изменить текст элементов Button и Label можно двойным щелчком мышки по каждому из них либо с помощью инспектора атрибутов: параметр Text для элемента Label и параметр Title для Button.

38.9. Доступ кода к UI. Определитель типа @IBOutlet

Вы уже знаете, как обеспечить доступ элементов сцены к методам класса (если кто забыл — с помощью определителя @IBAction). Для осуществления обратной операции (доступ к элементу из кода) служит ключевое слово @IBOutlet, называемое аутлетом.

Сейчас мы рассмотрим пример его использования: запрограммируем изменение текста метки, размещенной на сцене, по нажатии на кнопки Left и Right.

Измените режим отображения Project Editor на Assistant Editor, нажав кнопку Show the Assistant Editor на панели инструментов (Toolbar). После этого Project Editor будет разделен на две рабочие зоны. Вы можете изменять их размеры и подстраивать удобным для вас способом, а также скрывать другие панели.

Задание

С помощью панели Jump Bar, расположенной выше Project Editor, организуйте отображение Main.storyboard в левой зоне, а ViewController.swift — в правой (рис. 38.32).

Рис. 38.32. Assistant Editor в действии

Режим Assistant Editor предоставляет очень удобный способ создания экшенов и аутлетов. С зажатой клавишей Ctrl в IB выделите элемент Label, после чего перетащите его в соседнюю зону, в которой открыт файл ViewController.swift. Расположите появившуюся синюю линию выше метода showMessage(). При этом должна быть надпись «Insert Outlet or Outlet Collection» (рис. 38.33). После того как вы отпустите кнопку мышки, отобразится окно создания Outlet (рис. 38.34). Поле Connection определяет тип создаваемой связи. Выберите Outlet в качестве его значения. В поле Name укажите «label». Не изменяя значения остальных полей, нажмите кнопку Connect. После этого у класса ViewController будет создано новое свойство Label (листинг 38.10).

Рис. 38.33. Создание связи между кодом и элементом

Рис. 38.34. Окно создания Outlet

ПРИМЕЧАНИЕ В данном случае поле Connection не содержит значения Action. Это связано с тем, что Action в принципе не может быть создан для элемента Label. Если вы проделаете ту же операцию с кнопкой, то увидите Action в качестве доступного для выбора значения.

Листинг 38.10

class ViewController: UIViewController {

    @IBOutlet weak var label: UILabel!

    @IBAction func showMessage(){

    //...

    }

}

Свойство label содержит определитель типа @IBOutlet. Слева от него отображена пиктограмма в виде серого круга, указывающая на то, что свойство имеет настроенную связь с элементом. Если навести на свойство указатель мышки, то связанный с ним элемент будет подсвечен прямо на сцене в соседней рабочей зоне (речь, конечно же, идет о работе в режиме Assistant Editor) (рис. 38.35).

Рис. 38.35. Отображение связи между элементом и аутлетом

Следующим шагом в реализации функции смены текста метки станет создание action-метода changeLabelText() (метода c определителем @IBAction). Внутри своей реализации он будет использовать аутлет label для доступа к элементу Label и изменения свойства, отвечающего за его текст. На этот раз не станем создавать отдельный метод для каждой из кнопок — Xcode позволяет создать связь одного action-метода сразу с несколькими элементами на сцене.

Вполне возможно, у вас возник вопрос: как внутри метода будет определяться, какая из кнопок нажата? Дело в том, что метод, помеченный определителем @IBAction, позволяет использовать входной аргумент sender, содержащий ссылку на тот элемент, который вызвал данный метод. В качестве типа этого аргумента можно указать как какой-то конкретный (как, например, UIButton), так и AnyObject, позволяющий связать данный метод с любым типом элементов на сцене.

Вы уже умеете создавать action-методы вручную. Сейчас рассмотрим более удобный способ с использованием возможностей Assistant Editor. Ранее вы создавали аутлет с помощью перетаскивания элемента Label с зажатой клавишей Ctrl в область редактора кода. Удерживайте нажатой клавишу Ctrl, и перетащите кнопку Right прямо под созданное ранее свойство label. В появившемся окне в поле Connection вы сможете выбрать значение Action (рис. 38.36). В качестве имени укажите «changeLabelText», а в поле TypeUIButton (так как использовать данный метод будут исключительно кнопки). Поле Event позволяет указать тип события, по которому будет вызван данный Action, оставьте его без изменений. Обратите внимание на поле Arguments: если выбрать None, то создаваемый метод не будет иметь каких-либо входных аргументов, и мы не сможем определить, какая кнопка нажата. Для того чтобы action-метод мог обратиться к вызвавшему его элементу, в данном поле необходимо указать Sender. После нажатия кнопки Connect в редакторе кода появится новый метод changeLabelText(_:) с определителем типа @IBAction (листинг 38.11).

Рис. 38.36. Окно создания Action

Листинг 38.11

class ViewController: UIViewController {

   //...

   @IBAction func changeLabelText(_ sender: UIButton) {

   }

   //...

}

Внутри созданного метода вы можете обратиться к свойству label для доступа к элементу Label на сцене с целью изменения его параметров. Реализуем в методе функционал, изменяющий текст метки, используя при этом текст самой кнопки (листинг 38.12).

Листинг 38.12

@IBAction func changeLabelText(_ sender: UIButton) {

      label.text = ("The \(sender.titleLabel!.text!.lowercased()) button was pressed")

}

Аутлет-свойство label хранит в себе экземпляр класса UILabel, соответствующий элементу Label, расположенному на сцене, поэтому мы используем его для изменения текста метки (свойство text).

Рассмотрим подробнее выражение sender.titleLabel!.text!.lowercased(). Параметр sender позволяет обратиться к экземпляру класса UIButton, который соответствует той кнопке на сцене, которая была использована для вызова метода changeLabelText(_:) и передана в качестве входного аргумента. Свойство titleLabel возвращает опциональный экземпляр класса UILabel, который как раз и содержит описание текста кнопки. Для доступа к самому тексту используется свойство text, после чего происходит его преобразование к нижнему регистру с помощью метода lowercased(). Вот такая запутанная и одновременно простая цепочка.

Самое интересное в том, что созданный метод может быть использован в том числе и для кнопки Left, при этом свойство sender будет корректно отрабатывать и ее. Для создания связи между action-методом changeLabelText(_:) и кнопкой Left в режиме Assistant Editor достаточно нажать кнопку мыши на сером квадрате левее метода changeLabelText(_:) и перетащить его на элемент сцены (рис. 38.37). Теперь, если запустить программу и нажать на любую из двух кнопок, то текст метки будет изменяться.

Рис. 38.37. Создание дополнительной связи action-метода и Button

Возможно, что при изменении текста элемент не будет соответствовать размерам метки и не отобразится полностью. В этом случае необходимо растянуть элемент Label во всю ширину сцены и изменить свойство Alignment в инспекторе атрибутов на «выравнивание по центру».

Таким образом, мы разобрали с вами основы создания простейшего пользовательского интерфейса и связывания между собой кода и графических элементов. Я советую вам дальше самостоятельно тренироваться использовать другие объекты библиотеки UIKit, активно подключая официальную справку от Apple.

Назад: Часть VII. Введение в мобильную разработку
Дальше: 39. Паттерны проектирования при разработке в Xcode