На предыдущем уроке вы создали простой проект Swift в Xcode, базовом приложении для ведения дел. В этой части Swift From Scratch мы собираемся добавить возможность создавать задачи. По пути вы узнаете о действиях, делегировании и свойствах.
Предпосылки
Если вы хотите следовать за мной, убедитесь, что на вашем компьютере установлен Xcode 8.3.2 или выше. Вы можете скачать Xcode 8.3.2 из Apple App Store .
1. Добавление предметов
В конце этого урока пользователь сможет добавлять новые задачи, нажав кнопку на панели навигации, представив представление с текстовым полем и кнопкой. Давайте начнем с создания контроллера представления, который будет обрабатывать добавление новых дел, класса AddItemViewController
.
Шаг 1: Создать AddItemViewController
Выберите « Создать»> «Файл …» в меню « Файл» Xcode и выберите шаблон « Какао-класс касания» из списка iOS> Шаблоны источников .
Назовите класс AddItemViewController
и убедитесь, что он наследуется от UIViewController
. Дважды проверьте, что для языка установлено значение Swift и что также не создается файл XIB .
Укажите Xcode, где вы хотите сохранить файл для класса AddItemViewController
и нажмите « Создать» .
Шаг 2: Добавьте розетки и действия
Прежде чем мы создадим пользовательский интерфейс класса AddItemViewController
, нам нужно создать выход для текстового поля и два действия: одно для кнопки отмены на панели навигации и другое для кнопки создания под текстовым полем.
Добавление розетки должно быть уже знакомо. Создайте выход в классе AddItemViewController
и назовите его textField
как показано ниже.
01
02
03
04
05
06
07
08
09
10
11
12
13
|
class AddItemViewController: UIViewController {
@IBOutlet var textField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
|
Создание действия очень похоже на создание метода экземпляра. Фактически, атрибут @IBAction
является не более чем подсказкой для Interface Builder. @IBAction
метода с атрибутом @IBAction
гарантирует, что Interface Builder знает о методе, что позволяет нам подключать его в раскадровке. Мы пока оставим тела обоих действий пустыми.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
|
class AddItemViewController: UIViewController {
@IBOutlet var textField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
@IBAction func cancel(_ sender: Any) {
}
@IBAction func create(_ sender: Any) {
}
}
|
Шаг 3: Создайте пользовательский интерфейс
Откройте Main.storyboard в Навигаторе проекта и перетащите View Controller из Библиотеки объектов справа. С выбранным контроллером представления, откройте Identity Inspector справа и установите Custom Class> Class в AddItemViewController .
Чтобы добавить панель навигации к представлению добавления элемента, выберите контроллер представления « Добавить элемент» и выберите « Встроить»> «Контроллер навигации» в меню « Редактор» . Это сделает Add View View Controller корневым контроллером представления навигационного контроллера.
Следующим шагом является добавление элемента кнопки панели на панель навигации контроллера представления, а не добавления контроллера представления элемента, и установка его идентификатора на « Добавить» в инспекторе атрибутов .
Когда пользователь нажимает кнопку « Добавить», контроллер представления элемента должен быть представлен модально. Для этого нажмите клавишу « Control» и перетащите кнопку « Добавить» на контроллер навигации , выбрав « Представить модально» из всплывающего меню. Это создаст переход от контроллера представления элемента к новому контроллеру навигации .
Перетащите текстовое поле и кнопку из библиотеки объектов и добавьте их в сцену « Добавить элемент» . Выберите Add View View Controller и соедините выход textField
с текстовым полем и действие create(_:)
с кнопкой. Действие create(_:)
должно запускаться при возникновении события Touch Up Inside . Измените заголовок кнопки на « Создать» и добавьте необходимые ограничения макета в текстовое поле и кнопку.
Чтобы завершить работу с пользовательским интерфейсом, добавьте элемент кнопки панели в левом верхнем углу панели навигации контроллера представления элемента и установите для его идентификатора значение « Отмена» . При выбранном контроллере « Добавить элемент» откройте инспектор подключений и подключите cancel(_:)
действие на кнопку Отмена .
Создайте и запустите приложение, нажав Command-R, чтобы убедиться, что все правильно подключено.
2. Реализация протокола делегата
Когда пользователь нажимает кнопку « Создать» , чтобы добавить элемент списка дел, контроллер представления добавления элемента должен уведомить контроллер представления. Делегирование является идеальным решением для этого сценария. Процесс довольно прост.
Мы создаем протокол делегата, ViewController
соответствует класс ViewController
. Когда AddItemViewController
экземпляр AddItemViewController
когда пользователь нажимает кнопку « ViewController
объект ViewController
устанавливается как делегат экземпляра AddItemViewController
, что позволяет последнему уведомлять экземпляр ViewController
при создании нового элемента ViewController
. Давайте разберемся, чтобы лучше понять этот процесс.
Шаг 1. AddItemViewControllerDelegate
протокол AddItemViewControllerDelegate
Откройте AddItemViewController.swift и объявите протокол AddItemViewControllerDelegate
под оператором импорта в верхней части. Объявление протокола выглядит как объявление класса. За ключевым словом protocol
следует имя протокола.
1
2
3
4
5
6
7
|
import UIKit
protocol AddItemViewControllerDelegate {
func controller(_ controller: AddItemViewController, didAddItem: String)
}
|
Концепция очень похожа на протоколы в Objective-C. Название протокола AddItemViewControllerDelegate и определяет один метод, controller(_:didAddItem:)
.
Шаг 2: объявить свойство delegate
Объект, который должен реализовать протокол делегата, является делегатом AddItemViewController
. Сначала нам нужно создать свойство для делегата, как показано во фрагменте ниже.
1
2
3
4
5
6
7
8
|
class AddItemViewController: UIViewController {
@IBOutlet var textField: UITextField!
var delegate: AddItemViewControllerDelegate?
…
}
|
Свойство delegate
имеет тип AddItemViewControllerDelegate?
необязательный тип, поскольку мы не можем быть уверены, что свойство delegate
не равно nil
. Обратите внимание, что имя протокола не заключено в угловые скобки, как в Objective-C.
Шаг 3: Реализация действий
Метод делегата, controller(_:didAddItem:)
, будет вызван в действии create(_:)
как показано ниже. Для простоты примера мы не делаем никакой проверки на ввод пользователя.
Мы используем необязательную цепочку для вызова метода делегата на объекте делегата, что означает, что метод делегата вызывается только в том случае, если установлено свойство delegate
. Значение текстового поля временно сохраняется в константе, item
.
1
2
3
4
5
|
@IBAction func create(_ sender: Any) {
if let item = textField.text {
delegate?.controller(self, didAddItem: item)
}
}
|
Реализация действия cancel(_:)
очень проста. Все, что мы делаем, — AddItemViewController
экземпляр AddItemViewController
.
1
2
3
|
@IBAction func cancel(_ sender: Any) {
dismiss(animated: true)
}
|
Шаг 4: Установите делегата
Там один кусок головоломки отсутствует, хотя. Свойство delegate
экземпляра AddItemViewController
в данный момент не устанавливается. Мы можем решить эту проблему, реализовав метод prepare(for:sender:)
в классе ViewController
. Однако сначала нам нужно вернуться к раскадровке.
Откройте Main.storyboard и выберите переход, соединяющий кнопку Add с навигационным контроллером . Откройте Инспектор Атрибутов и установите Идентификатор перехода в AddItemViewController .
Затем реализуйте метод prepare(for:sender:)
в классе ViewController
как показано ниже. Обратите внимание на ключевое слово override
префикс метода. Это должно быть уже знакомо.
01
02
03
04
05
06
07
08
09
10
|
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == «AddItemViewController» {
let navigationController = segue.destination as?
let addItemViewController = navigationController?.topViewController as?
if let viewController = addItemViewController {
viewController.delegate = self
}
}
}
|
Мы начнем с проверки идентификатора перехода, чтобы убедиться, что мы готовимся к правильному переходу. Затем мы просим segue о его контроллере представления назначения. Вы можете ожидать, что это будет экземпляр AddItemViewController
, но помните, что мы сделали контроллер представления корневым контроллером представления контроллера навигации. Это означает, что нам нужно запросить у контроллера навигации, контроллера представления назначения segue, его контроллер вида сверху.
Константа addItemViewController
имеет тип AddItemViewController?
из-за использования as?
ключевое слово. Другими словами, используя as?
мы topViewController
свойства topViewController
до необязательного типа.
В операторе if
мы разворачиваем необязательное и устанавливаем свойство delegate
для экземпляра ViewController
.
Я уверен, что вы заметили использование нескольких опций в реализации метода prepare(for:sender:)
. При взаимодействии с API Objective-C всегда лучше не рисковать. Хотя отправка сообщений на nil
в Objective-C вполне возможна, в Swift — нет. Из-за этого ключевого различия вы всегда должны быть осторожны при взаимодействии с Objective-C API в Swift. Приведенный выше пример хорошо иллюстрирует это.
Шаг 5. Реализация протокола AddItemViewControllerDelegate
Реализация протокола AddItemViewControllerDelegate
аналогична реализации протокола UITableViewDataSource
. Мы начнем с согласования класса ViewController
с протоколом, как показано ниже.
1
2
3
|
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, AddItemViewControllerDelegate {
…
}
|
Затем мы реализуем методы протокола AddItemViewControllerDelegate
, который сводится к реализации метода controller(_:didAddItem:)
. Мы добавляем новый элемент в свойство items
контроллера представления, перезагружаем табличное представление и отклоняем контроллер представления add item.
01
02
03
04
05
06
07
08
09
10
11
12
|
// MARK: Add Item View Controller Delegate Methods
func controller(_ controller: AddItemViewController, didAddItem: String) {
// Update Data Source
items.append(didAddItem)
// Reload Table View
tableView.reloadData()
// Dismiss Add Item View Controller
dismiss(animated: true)
}
|
Шаг 6: Сборка и запуск
Создайте и запустите приложение, чтобы проверить, можете ли вы добавлять новые элементы в список дел. В настоящее время мы не проверяем ввод пользователя. В качестве упражнения, покажите пользователю предупреждение, если он нажал кнопку « Создать» , а текстовое поле пустое. Добавление пустого списка дел не очень полезно. Правильно?
Вывод
На этом уроке вы узнали, как объявлять и реализовывать собственный протокол. Вы также узнали, как создавать действия и подключать их в Интерфейсном Разработчике. На следующем уроке мы собираемся завершить наше приложение, добавив возможность удалять элементы, и мы также улучшим взаимодействие с приложением.
А пока ознакомьтесь с некоторыми другими нашими курсами и учебными пособиями по разработке iOS на языке Swift!