Статьи

iOS вкратце — Привет, iOS!

В этой статье мы познакомимся с тремя основными шаблонами проектирования, лежащими в основе всей разработки приложений для iOS: модель-представление-контроллер, объекты-делегаты и цель-действие.

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

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


Во-первых, нам нужно создать новый проект Xcode. Откройте Xcode и перейдите в « Файл»> «Создать»> «Проект» или нажмите Cmd + Shift + N, чтобы открыть экран выбора шаблона. В этой главе мы создадим простейшую из возможных программ: приложение с одним представлением. Выберите шаблон и нажмите кнопку «Далее».

tutorial_image
Рисунок 2: Выбор шаблона приложения Single View

Используйте HelloWorld в качестве названия продукта , все, что вам нравится в качестве имени организации , и edu.self в качестве идентификатора компании . Убедитесь, что для устройства установлено значение « iPhone» и выбраны « Использовать раскадровки» и « Использовать автоматический подсчет ссылок».

tutorial_image
Рисунок 3: Конфигурация для нашего приложения HelloWorld

После выбора места для сохранения файла у вас будет самое первое приложение для iOS, с которым можно поэкспериментировать.


Как мы видели в приложении командной строки в Objective-C вкратце, вы можете скомпилировать проект, нажав кнопку «Выполнить» в верхнем левом углу Xcode или используя сочетание клавиш Cmd + R. Но, в отличие от Objective-C, лаконично, наше приложение представляет собой графическую программу, предназначенную для iPhone. Вместо того, чтобы просто скомпилировать код и выполнить его, Xcode запускает его с помощью приложения iOS Simulator. Это позволяет нам видеть, как наше приложение будет выглядеть на iPhone без необходимости загружать его на реальное устройство каждый раз, когда мы вносим малейшие изменения. Шаблон, который мы использовали, является пустым проектом, поэтому при запуске вы увидите только белый экран.

tutorial_image
Рисунок 4: Запуск проекта HelloWorld в симуляторе iOS

В то время как мы не можем точно сказать с нашим текущим приложением, симулятор является довольно подробной копией реальной среды iPhone. Вы можете нажать кнопку «Домой», которая отобразит все приложения, которые мы запустили в симуляторе, а также несколько встроенных. Как мы увидим через мгновение, это позволяет нам тестировать различные состояния нашего приложения.


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

Как и в любой программе Objective-C, приложение запускается в функции main () main.m. Файл main.m для нашего проекта HelloWorld можно найти в папке « Вспомогательные файлы » на панели «Навигатор проектов» в Xcode. Код по умолчанию, предоставленный вашим шаблоном, должен выглядеть следующим образом.

01
02
03
04
05
06
07
08
09
10
11
12
#import <UIKit/UIKit.h>
 
#import «AppDelegate.h»
 
int main(int argc, char *argv[]) {
    @autoreleasepool {
        return UIApplicationMain(argc,
                                 argv,
                                 nil,
                                 NSStringFromClass([AppDelegate class]));
    }
}

Это запускает ваше приложение, вызывая функцию UIApplicationMain () и передавая [класс AppDelegate] в качестве последнего аргумента, сообщая приложению о передаче управления нашему классу AppDelegate . Мы обсудим это подробнее в следующем разделе.

Для большинства приложений вам никогда не придется менять main.m по умолчанию. Любую пользовательскую настройку можно отложить до классов AppDelegate или ViewController.

Архитектура iOS в значительной степени опирается на шаблон проектирования делегатов. Этот шаблон позволяет объекту передавать управление некоторыми своими задачами другому объекту. Например, каждое приложение iOS внутренне представлено как объект UIApplication, но разработчики редко создают экземпляр UIApplication напрямую. Вместо этого функция UIApplicationMain () в main.m создает ее для вас и указывает на объект делегата, который затем служит корнем приложения. В экземпляре нашего проекта HelloWorld экземпляр пользовательского класса AppDelegate действует как объект делегата.

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

tutorial_image
Рисунок 5: Использование AppDelegate в качестве объекта делегата для UIApplication

Вспомните из Objective-C. Кратко, что протокол объявляет произвольную группу методов или свойств, которые может реализовать любой класс. Поскольку делегат предназначен для управления произвольным набором задач, это делает протоколы логическим выбором для представления делегатов. Протокол UIApplicationDelegate объявляет методы, которые должен определить делегат для UIApplication, и мы видим, что наш класс AppDelegate принимает его в AppDelegate.h.

1
@interface AppDelegate : UIResponder <UIApplicationDelegate>

Это то, что формально превращает наш класс AppDelegate в делегат для основного экземпляра UIApplication. Если вы откроете AppDelegate.m, вы также увидите заглушки для реализации следующих методов:

1
2
3
4
5
6
7
— (BOOL)application:(UIApplication *)application
        didFinishLaunchingWithOptions:(NSDictionary *)launchOptions;
— (void)applicationWillResignActive:(UIApplication *)application;
— (void)applicationDidEnterBackground:(UIApplication *)application;
— (void)applicationWillEnterForeground:(UIApplication *)application;
— (void)applicationDidBecomeActive:(UIApplication *)application;
— (void)applicationWillTerminate:(UIApplication *)application;

Эти методы вызываются UIApplication, когда определенные события происходят внутри. Например, метод application: didFinishLaunchingWithOptions: вызывается сразу после запуска приложения. Давайте посмотрим, как это работает, добавив вызов NSLog () для некоторых из этих методов.

01
02
03
04
05
06
07
08
09
10
11
— (BOOL)application:(UIApplication *)application
        didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    NSLog(@»Application has been launched»);
    return YES;
}
— (void)applicationDidEnterBackground:(UIApplication *)application {
    NSLog(@»Entering background»);
}
— (void)applicationWillEnterForeground:(UIApplication *)application {
    NSLog(@»Entering foreground»);
}

Теперь, когда вы компилируете проект и запускаете его в iOS Simulator, вы должны увидеть, что приложение было запущено сразу после его открытия. Вы можете нажать кнопку «Домой» на симуляторе, чтобы переместить приложение в фоновый режим, и щелкнуть значок приложения на главном экране, чтобы переместить его обратно на передний план. Внутренне, нажатие кнопки home вызывает вызов экземпляра UIApplication applicationDidEnterBackground ::

tutorial_image
Рисунок 6: Перемещение приложения HelloWorld в фоновый режим

Это должно отобразить следующие сообщения на панели вывода Xcode.

tutorial_image
Рисунок 7: Вывод Xcode после нажатия кнопки home в iOS Simulator

Эти сообщения NSLog () показывают нам основные механизмы, лежащие в основе делегата приложения, но в реальном мире вы бы написали пользовательский код установки и очистки для этих методов. Например, если вы создавали трехмерное приложение с OpenGL, вам необходимо остановить рендеринг контента и освободить все связанные ресурсы в методе applicationDidEnterBackground:. Это гарантирует, что ваше приложение не перегружает память после того, как пользователь ее закроет.

Подводя итог, наш класс AppDelegate служит практической точкой входа в наше приложение. Его задача — определить, что происходит, когда приложение открывается, закрывается или переходит в ряд других состояний. Это достигается путем использования в качестве делегата для экземпляра UIApplication, который является внутренним представлением всего приложения.

Вне делегата приложения iOS-приложения следуют шаблону проектирования модель-представление-контроллер (MVC). Модель инкапсулирует данные приложения, представление представляет собой графическое представление этих данных, а контроллер управляет компонентами модели / представления и обрабатывает вводимые пользователем данные.

tutorial_image
Рисунок 8: Шаблон модель-представление-контроллер, используемый приложениями для iOS

Данные модели обычно представлены в виде файлов, объектов из инфраструктуры CoreData или пользовательских объектов. Приложение, которое мы создаем в этой главе, не нуждается в выделенном компоненте модели; мы сосредоточимся на аспектах вида и контроллера шаблона MVC до следующей главы.

Компоненты представления представлены классом UIView. Его UIButton, UILabel, UITextField и другие подклассы представляют конкретные типы компонентов пользовательского интерфейса, а сам UIView может выступать в качестве универсального контейнера для всех этих объектов. Это означает, что сборка пользовательского интерфейса — это всего лишь вопрос настройки экземпляров UIView. В нашем примере ViewController автоматически создает корневой экземпляр UIView, поэтому нам не нужно создавать его экземпляр вручную.

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

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

В то время как AppDelegate является программной точкой входа в приложение, наш ViewController является графическим корнем проекта. Метод viewDidLoad в ViewController.m вызывается после загрузки корневого экземпляра UIView. Здесь мы можем создавать новые компоненты пользовательского интерфейса и добавлять их на сцену (мы сделаем это через минуту).

Последний файл, на который мы должны обратить внимание, — это MainStoryboard.storyboard. Это специальный тип файла, который хранит весь поток вашего приложения и позволяет редактировать его визуально, а не программно. Выбор этого в Project Navigator Xcode откроет Интерфейсный Разработчик вместо обычного редактора исходного кода, который должен выглядеть примерно так:

tutorial_image
Рисунок 9: Интерфейсный Разработчик нашего проекта HelloWorld

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

Прежде чем мы начнем добавлять кнопки и текстовые поля, давайте на минутку рассмотрим крайний левый желтый значок в доке. Сначала убедитесь, что панель «Утилиты» открыта, переключив крайнюю правую кнопку на вкладке «Вид»:

tutorial_image
Рисунок 10: Отображение панели Utilities (выделено оранжевым)

Затем щелкните желтый значок в доке, чтобы выбрать его:

tutorial_image
Рисунок 11: Выбор значка View Controller

Этот значок представляет контроллер для сцены. Для нашего проекта это экземпляр пользовательского класса ViewController. Мы можем убедиться в этом, выбрав инспектор удостоверений на панели «Утилиты», который отобразит класс, связанный с контроллером:

tutorial_image
Рисунок 12. Инспектор удостоверений на панели «Утилиты»

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

Также стоит взглянуть на инспектора Атрибутов , который является следующей вкладкой на панели Утилиты .

tutorial_image
Рисунок 13: Инспектор атрибутов для контроллера

Флажок «Это начальный вид контроллера» делает эту сцену корневой. Каждое приложение должно иметь ровно одну корневую сцену, иначе iOS не будет знать, как запустить ваше приложение. Если вы снимите флажок, стрелка, указывающая на сцену, исчезнет, ​​и вы получите следующее сообщение при попытке скомпилировать проект.

tutorial_image
Рисунок 14: Сообщение об ошибке от отсутствующей корневой сцены

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


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

Мы начнем с программного метода, поскольку он показывает нам, что происходит за кулисами, когда мы создаем макеты с помощью Interface Builder. Помните, что одной из основных задач нашего ViewController является управление компонентами пользовательского интерфейса, поэтому именно здесь мы должны создать наш макет. В ViewController.m измените метод viewDidLoad на следующий.

1
2
3
4
5
6
7
8
— (void)viewDidLoad {
    [super viewDidLoad];
     
    UIButton *aButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
    [aButton setTitle:@»Say Hello» forState:UIControlStateNormal];
    aButton.frame = CGRectMake(100.0, 200.0, 120.0, 40.0);
    [[self view] addSubview:aButton];
}

Сначала мы создаем объект UIButton, который является объектно-ориентированным представлением кнопки. Затем мы определяем его метку, используя setTitle: forState: метод. Константа UIControlStateNormal указывает кнопке использовать это значение для состояния «вверх». Все графические компоненты используют свойство frame для определения их положения и местоположения. Он принимает структуру CGRect, которую можно создать с помощью вспомогательной функции CGRectMake () . Предыдущий пример говорит кнопке позиционировать себя в (x = 100, y = 200) и использовать ширину 120 пикселей и высоту 40 пикселей. Наиболее важной частью является строка [[self view] addSubview: aButton] . Это добавляет новый объект UIButton к корневому экземпляру UIView, доступ к которому осуществляется через свойство view нашего ViewController.

После компиляции проекта вы должны увидеть кнопку посередине симулятора iOS.

tutorial_image
Рисунок 15: Программное создание UIButton

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

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

Создание компонентов в Интерфейсном Разработчике немного более интуитивно понятно, чем программный метод, но, по сути, делает то же самое за кулисами. Все, что вам нужно сделать, это перетащить компонент из библиотеки объектов на сцену. Библиотека объектов находится в нижней части панели «Утилиты» и выглядит примерно так:

tutorial_image
Рисунок 16: Библиотека объектов

На предыдущем скриншоте мы выбрали отображение только элементов управления пользовательского интерфейса, выбрав «Элементы управления» в раскрывающемся меню. Это основные графические компоненты для запроса ввода от пользователя.

Давайте добавим еще одну кнопку, а также компонент «Метка» и «Текстовое поле», перетащив связанные объекты из библиотеки в большую белую область, представляющую корневую сцену. После того, как они окажутся на сцене, вы можете расположить их, перетаскивая их, и вы можете изменить их размер, щелкнув целевой компонент, а затем перетащив белые квадраты, окружающие его. При перемещении компонентов вы увидите пунктирные ориентиры, которые помогут вам выровнять элементы и создать согласованные поля. Постарайтесь, чтобы ваш макет выглядел примерно так, как показано на рисунке 17. Кнопка «Скажите до свидания» должна быть центрирована как по оси x, так и по оси y:

tutorial_image
Рисунок 17: Расположение компонентов Button, Label и Text Field

Чтобы изменить текст в кнопке, просто дважды щелкните по нему и введите желаемый заголовок (в этом случае скажите «До свидания»). Интерфейсный Разработчик также предоставляет несколько других инструментов для редактирования внешнего вида и поведения компонента. Например, вы можете установить заполнитель текста нашего текстового поля на панели атрибутов. Попробуйте изменить его на Ваше имя:

tutorial_image
Рисунок 18: Определение текста заполнителя

Это будет отображать некоторый инструктивный текст, когда поле пустое, что обычно является хорошей идеей с точки зрения пользовательского опыта. Когда вы компилируете свое приложение, оно должно выглядеть примерно так (обратите внимание, что мы все еще используем кнопку Say Hello, которую мы добавили в viewDidLoad).

tutorial_image
Рисунок 19: Приложение HelloWorld

Если вы щелкнете по текстовому полю в iOS Simulator, он откроет клавиатуру, как вы ожидаете от любого приложения iOS. Вы сможете вводить текст, но не сможете отклонить клавиатуру. Мы исправим эту проблему в разделе «Делегаты» следующего раздела. До этого не нажимайте текстовое поле во время тестирования приложения.

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

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


В этом разделе рассматриваются три наиболее важных типа соединений между вашим исходным кодом и компонентами пользовательского интерфейса: действия, выходы и делегаты. Действие — это метод, который следует вызывать, когда происходит определенное событие (например, когда пользователь нажимает кнопку). Розетка соединяет переменную исходного кода с графическим компонентом в Интерфейсном Разработчике. Мы уже работали с делегатами в классе AppDelegate, но этот шаблон проектирования также распространен в графических аспектах iOS. Это позволяет вам управлять поведением компонента из произвольного объекта (например, нашего пользовательского ViewController).

Точно так же, как добавление компонентов в макет, подключение их к вашим пользовательским классам может быть сделано либо программно, либо через Interface Builder. Мы представим оба метода в следующем разделе Действия, но будем полагаться на Интерфейсный Разработчик для выходов и делегатов.

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

Программные действия

Класс UIControl, от которого наследуется UIButton, определяет метод addTarget: action: forControlEvents:, который позволяет вам присоединить пару target-action к событию. Например, мы можем заставить нашу кнопку Say Hello отображать приветствие при нажатии на нее, изменив метод viewDidLoad в ViewController.m на следующий.

01
02
03
04
05
06
07
08
09
10
11
12
— (void)viewDidLoad {
    [super viewDidLoad];
     
    UIButton *aButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
    [aButton setTitle:@»Say Hello» forState:UIControlStateNormal];
    aButton.frame = CGRectMake(100.0, 200.0, 120.0, 40.0);
    [[self view] addSubview:aButton];
    // Configure an action.
    [aButton addTarget:self
                action:@selector(sayHello:)
      forControlEvents:UIControlEventTouchUpInside];
}

Этот код сообщает кнопке для вызова sayHello: метод для self, когда происходит событие UIControlEventTouchUpInside . Это событие срабатывает, когда пользователь отпускает прикосновение к внутренней части кнопки. Другие события определяются перечислением UIControlEvents, содержащимся в UIControl.

Конечно, чтобы пара target-action в предыдущем примере кода работала, нам нужно определить метод действия. Действие должно принимать один аргумент, представляющий компонент пользовательского интерфейса, который вызвал событие. Добавьте следующий метод к ViewController.m .

1
2
3
— (void)sayHello:(id)sender {
    NSLog(@»Hello, World!»);
}

Теперь, когда вы скомпилируете проект и нажмете кнопку «Скажи привет» в симуляторе iOS, он должен отобразить Hello, World! в панели вывода Xcode. Если вам нужно получить доступ к кнопке UIB, которая вызвала событие, вы можете сделать это с помощью аргумента отправителя. Это может быть полезно, например, когда вы хотите отключить кнопку после того, как пользователь щелкнет по ней.

Настройка действий через Интерфейсный Разработчик занимает еще пару шагов, но она более интуитивна при работе с компонентами, которые не были созданы программно. В этом разделе мы будем использовать Интерфейсный Разработчик, чтобы создать действие для кнопки Say Goodbye.
Действия должны быть объявлены публично, поэтому наша первая задача — добавить метод действия в ViewController.h .

1
— (IBAction)sayGoodbye:(id)sender;

Обратите внимание на тип возврата IBAction. Технически это просто typedef для void; однако использование его в качестве возвращаемого типа заставляет Xcode и Interface Builder осознавать тот факт, что это должно быть действие, а не просто обычный метод. Это отражается маленьким кружком, который появляется рядом с методом в редакторе исходного кода.

tutorial_image
Рисунок 20: Xcode, распознающий метод как действие

Далее нам нужно реализовать метод действия. В ViewController.m добавьте следующий метод.

1
2
3
— (IBAction)sayGoodbye:(id)sender {
    NSLog(@»See you later!»);
}

Вместо того, чтобы присоединять его программно с помощью addTarget: action: forControlEvents:, мы будем использовать Interface Builder, чтобы подключить этот метод к кнопке Say Goodbye. Выберите файл MainStoryboard.storyboard, чтобы открыть Interface Builder, и выберите желтый значок View Controller в док-станции.

tutorial_image
Рисунок 21: Выбор значка View Controller

Затем откройте инспектор соединений, который является самой правой вкладкой на панели «Утилиты».

tutorial_image
Рисунок 22: Вкладка «Подключения» на панели «Утилиты»

Эта панель содержит все отношения, доступные нашему классу ViewController. Обратите внимание на sayGoodbye: метод, указанный в разделе «Полученные действия». Это доступно только потому, что мы использовали возвращаемый тип IBAction в объявлении метода.

Чтобы создать связь между методом sayGoodbye: и кнопкой Say Goodbye, щелкните кружок рядом со словом say Goodbye: на панели «Соединения», а затем перетащите его на кнопку на сцене. Вы должны увидеть синюю линию при перетаскивании, как показано на следующем рисунке.

tutorial_image
Рисунок 23: Подключение sayGoodbye: метод к UIButton в Интерфейсном Разработчике

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

tutorial_image
Рисунок 24: Выбор события для действия

Выберите Touch Up Inside, который является эквивалентом перечислителя UIControlEventTouchUpInside, который мы использовали в предыдущем разделе. Это создает целевое соединение между ViewController и экземпляром UIButton. По сути, это точно такой же addTarget: action: forControlEvents: вызов, который мы использовали для кнопки Say Hello в предыдущем разделе, но мы сделали это полностью через Interface Builder. Теперь вы сможете скомпилировать проект и нажать кнопку «Скажите до свидания», чтобы увидеть « Увидимся позже!». сообщение на панели вывода.

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

Розетка — это более простой тип соединения, который связывает переменную исходного кода с компонентом пользовательского интерфейса. Это важная способность, поскольку она позволяет вам получать доступ к свойствам раскадровки и управлять ими из пользовательских классов. Розетки всегда происходят из пользовательского класса и принимаются компонентом пользовательского интерфейса в Интерфейсном Разработчике. Например, этот раздел создает выход из переменной с именем messageLabel для компонента UILabel в раскадровке. Это можно представить следующим образом:

tutorial_image
Рисунок 25: Создание выхода из класса ViewController в компонент метки

Для создания торговой точки сначала необходимо объявить свойство, которое будет связано с компонентом пользовательского интерфейса. Розетки обычно настраиваются в контроллере, поэтому откройте ViewController.h и добавьте следующее свойство.

1
@property (weak, nonatomic) IBOutlet UILabel *messageLabel;

Это похоже на любое другое объявление свойства, за исключением нового квалификатора IBOutlet. Как и IBAction, это обозначает свойство как выход и делает его доступным через Interface Builder, но не влияет на саму переменную. После того, как мы установили соединение, мы можем использовать messageLabel в качестве прямой ссылки на экземпляр UILabel, который мы добавили в раскадровку.

Но прежде чем мы это сделаем, нам нужно синтезировать методы доступа в ViewController.m:

1
@synthesize messageLabel = _messageLabel;

Вернувшись в MainStoryboard.storyboard , снова выберите желтый значок View Controller и взгляните на инспектор соединений.

tutorial_image
Рисунок 26: Инспектор соединений после добавления messageLabel в ViewController

Обратите внимание, как только что созданное нами свойство messageLabel отображается в списке Outlets. Теперь мы можем подключить его к компоненту пользовательского интерфейса, как мы это делали с действием кнопки в предыдущем разделе. Нажмите и перетащите от круга рядом с messageLabel к UILabel в сцене, вот так:

tutorial_image
Рисунок 27: Связывание messageLabel с экземпляром UILabel

Когда вы отпустите кнопку мыши, розетка будет создана, и вы можете использовать messageLabel для установки свойств экземпляра UILabel в Интерфейсном Разработчике. Например, попробуйте изменить текст и цвет надписи в sayHello: и sayGoodbye: методы ViewController.m:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
— (void)sayHello:(id)sender {
    _messageLabel.text = @»Hello, World!»;
    _messageLabel.textColor = [UIColor colorWithRed:0.0
                                              green:0.3
                                               blue:1.0
                                              alpha:1.0];
}
 
— (IBAction)sayGoodbye:(id)sender {
    _messageLabel.text = @»See you later!»;
    _messageLabel.textColor = [UIColor colorWithRed:1.0
                                              green:0.0
                                               blue:0.0
                                              alpha:1.0];
}

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

Прежде чем мы продолжим делегировать соединения, нам нужно настроить другой выход для UITextField, который мы добавили в Interface Builder. Это будет точно такой же процесс, как UILabel. Сначала объявите свойство и синтезируйте его методы доступа:

1
2
3
4
// ViewController.h
@property (weak, nonatomic) IBOutlet UITextField *nameField;
// ViewController.m
@synthesize nameField = _nameField;

Затем откройте Interface Builder, выберите желтый значок View Controller в док-станции и убедитесь, что инспектор Connections виден. Чтобы создать соединение, щелкните и перетащите от круга рядом с nameField к компоненту текстового поля в сцене. В следующем разделе этот выход позволит нам получить доступ к тексту, введенному пользователем.

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

Во-первых, давайте превратим класс ViewController в формальный делегат для текстового поля. Помните, что шаблон проектирования делегата реализован с помощью протоколов, поэтому все, что нам нужно сделать, это сказать ViewController.h принять протокол UITextFieldDelegate, например, так:

1
@interface ViewController : UIViewController <UITextFieldDelegate>

Далее нам нужно соединить текстовое поле и класс ViewController с помощью Interface Builder. Это соединение идет в направлении, противоположном выходам, которые мы создали в предыдущем разделе, поэтому вместо перетаскивания из ViewController в компонент пользовательского интерфейса нам нужно перетащить из текстового поля в ViewController. В Интерфейсном Разработчике выберите компонент текстового поля и откройте панель «Соединения». Вы должны увидеть поле делегата в разделе Outlets:

tutorial_image
Рисунок 28: Начало панели «Подключения» для компонента «Текстовое поле»

Чтобы создать подключение делегата, перетащите его из круга рядом с делегатом на желтый значок View Controller в доке:

tutorial_image
Рисунок 29: Создание подключения делегата из текстового поля к контроллеру представления

Теперь ViewController может управлять поведением текстового поля путем реализации методов, определенных в UITextFieldDelegate. Нас интересует метод textFieldShouldReturn:, который вызывается, когда пользователь нажимает кнопку «Возврат» на клавиатуре. В ViewController.m реализуйте метод следующим образом:

1
2
3
4
5
6
7
— (BOOL)textFieldShouldReturn:(UITextField *)textField {
    self.name = textField.text;
    if (textField == self.nameField) {
        [textField resignFirstResponder];
    }
    return YES;
}

Это сохраняет введенное пользователем значение ( textField.text ) в свойстве name после того, как они нажали кнопку Return. Затем мы заставляем клавиатуру исчезать, удаляя фокус из текстового поля с помощью метода resignFirstResponder. Условие textField == self.nameField — это лучший способ убедиться, что мы работаем с правильным компонентом (на самом деле в этом нет необходимости, если ViewController не является делегатом для нескольких текстовых полей). Обратите внимание, что мы все еще должны объявить это поле имени в ViewController.h:

1
@property (copy, nonatomic) NSString *name;

Таким способом лучше всегда изолировать данные модели в выделенных свойствах, а не полагаться непосредственно на значения, хранящиеся в компонентах пользовательского интерфейса. Это гарантирует, что они будут доступны, даже если за это время компонент пользовательского интерфейса был удален или изменен. Наш последний шаг — использовать это новое свойство name для персонализации сообщений в sayHello: и sayGoodbye :. В ViewController.m измените эти два метода на следующие:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
— (void)sayHello:(id)sender {
    if ([self.name length] == 0) {
        self.name = @»World»;
    }
    _messageLabel.text = [NSString stringWithFormat:@»Hello, %@!»
                                                    self.name];
    _messageLabel.textColor = [UIColor colorWithRed:0.0
                                              green:0.3
                                               blue:1.0
                                              alpha:1.0];
}
 
— (IBAction)sayGoodbye:(id)sender {
    if ([self.name length] == 0) {
        self.name = @»World»;
    }
    _messageLabel.text = [NSString stringWithFormat:@»See you later, %@!»,
                                                    self.name];
    _messageLabel.textColor = [UIColor colorWithRed:1.0
                                              green:0.0
                                               blue:0.0
                                              alpha:1.0];
}

Теперь вы сможете скомпилировать приложение, отредактировать компонент текстового поля, закрыть клавиатуру и увидеть полученное значение при нажатии кнопок «Скажите привет» и «Скажите до свидания».

tutorial_image
Рисунок 30: Реализация компонента Text Field

В этой главе были представлены основы разработки под iOS. Мы узнали об основной файловой структуре проекта: основной файл, делегат приложения, пользовательский контроллер представления и раскадровка. Мы также разработали макет, программно добавляя компоненты на сцену, а также визуально редактируя компоненты в Интерфейсном Разработчике. И чтобы наш код мог взаимодействовать с кнопками, надписями и текстовыми полями в раскадровке, мы создали подключения действий, выпусков и делегатов с помощью Interface Builder.

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

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

Этот урок представляет собой главу из iOS, сжатой , бесплатной электронной книги от команды Syncfusion .