Книга: Swift. Основы разработки приложений под iOS, iPadOS и macOS. 5-е изд. дополненное и переработанное
Назад: Часть II. Базовые возможности Swift
Дальше: 5. Фундаментальные типы данных

4. Отправная точка

У каждого из вас свой уровень подготовки и разный опыт за плечами, каждый прошел свой собственный путь независимо от других. Все это накладывает определенные сложности при написании учебного материала: для кого-то он может быть слишком простым, а для кого-то чрезвычайно сложным! Найти золотую середину порой не так просто.

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

4.1. Как компьютер работает с данными

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

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

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

Рис. 4.1. Функциональные уровни компьютера

Аппаратный уровень представляет собой набор типовых блоков (физического оборудования), самыми важными из которых являются центральный процессор (CPU, Central Processing Unit) и оперативная память.

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

CPU как раз и предназначен для работы с числами. Он получает на вход несколько значений и в зависимости от переданной команды выполняет с ними заданные операции.

В ходе этой работы в качестве временного хранилища данных выступает оперативная память. CPU постоянно производит с ней обмен данными.

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

Рассмотрим принцип работы оперативной памяти. На рис. 4.2 приведен схематичный вид памяти с ячейками № 1669–1680. В настоящее время эти ячейки пусты, то есть не имеют записанной в них информации.

Рис. 4.2. Память с набором ячеек

ПРИМЕЧАНИЕ Приведенные схемы и описания максимально упрощены. На самом деле компьютер на аппаратном уровне оперирует исключительно двумя цифрами: 0 и 1. Он знает всю их мощь и по полной их использует.

Приведенные далее примеры хранения и обработки десятичных чисел показаны для лучшего восприятия вами учебного материала. Повторюсь, что в действительности эти числа переводятся в двоичную систему, после чего происходит их запись в память и обработка в процессоре в виде последовательностей 0 и 1.

Предположим, что вы запустили программу «Калькулятор». При ее использовании возникает необходимость временно хранить в памяти различные числовые значения. Каждое значение при этом, скорее всего, будет занимать не одну, а целую группу ячеек (логически объединенных). Каждая такая группа будет иметь уникальное имя, она может быть названа хранилищем данных. Данные об используемых в программе хранилищах записываются в специальный реестр. При этом указывается имя хранилища, а также адреса используемых ячеек.

Предположим, было создано два хранилища с именами «Группа 1» и «Группа 2». В первом содержится числовое значение 23, а во втором — 145 (рис. 4.3).

В будущем для того, чтобы получить значение 23 (хранящееся в «Группе 1»), нет необходимости сканировать все ячейки оперативной памяти на предмет записанных в них данных — достаточно лишь обратиться к «Группе 1» по имени и получить записанное в ее ячейках значение.

Рис. 4.3. Реестр с двумя хранилищами данных

Если вернуться к рис. 4.1, то вторым идет уровень операционной системы. В ходе разработки вы будете не так часто задумываться о нем.

В общем случае операционная система — это посредник между вашей программой и аппаратной частью. Благодаря ОС, приложения могут использовать все возможности компьютера: выполнение математических операций, передача данных по Wi-Fi и Bluetooth, отображение графики, воспроизведение песен группы Queen и многое-многое другое.

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

Для того чтобы отдавать различные команды на выполнение каких-либо операций, как раз и нужен третий уровень (см. рис. 4.1).

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

В общем виде программирование — это автоматизация процессов для решения определенных задач с помощью компьютера. В ходе написания программы разработчик манипулирует данными и определяет реакцию программы на них.

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

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

4.2. Базовые понятия

В предыдущем разделе, когда мы говорили об оперативной памяти, то упоминали понятие «хранилище данных».

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

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

В программировании Swift при работе с хранилищами данных выделяют два важнейших понятия: объявление и инициализация.

Объявление — это создание нового объекта (хранилища данных).

Инициализация — это присвоение объявленному объекту определенного значения.

В примере выше были объявлены хранилища данных с именами «Группа 1» и «Группа 2», после чего их проинициализировали значениями 23 и 145.

Рассмотрим простейший арифметический пример: значение «Группы 1» (23) умножить на значение «Группы 2» (145) (листинг 4.1).

Листинг 4.1.

23 * 145

Данный математический пример является выражением, то есть законченной командой на языке математики. В нем можно выделить одну операцию умножения и два операнда, с которыми будут производиться действия (23 и 145).

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

• Получить значение «Группы 1».

• Получить значение «Группы 2».

• Произвести операцию умножения значения «Группы 1» на значение «Группы 2».

• Объявить хранилище данных с именем «Группа 3» для хранения результата умножения.

• Проинициализировать хранилищу «Группа 3» результат операции.

В листинге 4.1 указателем на то, что необходимо произвести операцию умножения, служит оператор * (умножение). В результате выполнения выражения будет получено новое значение 3335, записанное в группу ячеек с именем «Группа 3» (рис. 4.4).

Рис. 4.4. Результат умножения двух чисел помещен в новое хранилище

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

Любая программа — это набор выражений или, другими словами, набор четких команд, понятных компьютеру. Например, выражение «Отправь этот документ на печать» укажет компьютеру на необходимость выполнения некоторых действий в определенном порядке: загрузка документа, поиск принтера, отправка документа принтеру и т.д. Выражения могут состоять как из одной, так и из нескольких команд, как, например: «Отправь этот файл, но перед этим преобразуй его из docx в rtf».

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

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

Операнд — это значение, с которым оператор производит операцию.

Все зарезервированные языком программирования наборы символов называются ключевыми словами.

Ранее мы рассматривали пример умножения двух чисел 23 и 145 с последующим объявлением нового хранилища. Всего было выделено пять отдельных шагов, которые, в свою очередь, и являлись полноценным выражением.

Если рассмотреть это выражение со стороны синтаксиса языка программирования, то его можно представить в виде следующей строки (листинг 4.2).

Листинг 4.2

Создать_хранилище Группа 3 = Группа 1 * Группа 2

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

4.3. Введение в операторы

В Swift выделяют следующие основные виды операторов:

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

• Унарные операторы выполняют операцию с одним операндом (например, -a). Они могут находиться перед операндом, то есть быть префиксными (например, !b), или после него, то есть быть постфиксными (например, i?).

• Бинарные операторы выполняют операцию с двумя операндами (например, 1+6). Оператор, который располагается между операндами, называется инфиксным.

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

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

Обратимся к Swift и Xcode Playground. Перед вами уже должен быть открыт созданный ранее проект.

ПРИМЕЧАНИЕ Если вы закрыли предыдущий playground-проект, то создайте новый. Для этого откройте Xcode, в появившемся меню выберите пункт «Get started with a playground», после чего выберите Blank и укажите произвольное название нового проекта. Перед вами откроется рабочее окно Xcode playground (рис. 4.5).

Рис. 4.5. Окно нового playground

Взгляните на код в Xcode Playground (листинг 4.3).

Листинг 4.3

import UIKit

var str = "Hello World"

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

Рассмотрим следующую строчку кода (листинг 4.4).

Листинг 4.4

var str = "Hello World"

В ней объявляется хранилище данных, после чего инициализируется текстовое значение Hello World. Данное выражение можно разбить на отдельные шаги (рис. 4.6).

Рис. 4.6. Выражение состоит из отдельных шагов

Шаг 1: С помощью ключевого слова (оператора) var объявляется новое хранилище данных с именем str.

Шаг 2: В оперативную память записывается текстовое значение Hello World, после чего создается указатель в хранилище данных на этот участок памяти. Или, другими словами, в созданное хранилище str записывается значение Hello World. Этот процесс и называется инициализацией значения с помощью оператора = (присваивания).

Если представить текущую схему оперативной памяти, то она выглядит так, как показано на рис. 4.7.

Рис. 4.7. Результат создания нового хранилища данных

В данном выражении используется два оператора. На шаге 1 — это оператор var, на шаге 2 — оператор =. В двух следующих разделах рассмотрим подробнее их работу, но начнем с оператора инициализации.

4.4. Оператор инициализации

Напомню, что для хранения данных компьютер использует оперативную память, выделяя под каждое значение группу ячеек (хранилище данных), имеющую уникальное имя. Прежде чем говорить о том, каким образом в Swift объявляются хранилища, разберемся, каким образом данные могут быть записаны в эти хранилища. Для этого вернемся к выражению в Xcode Playground (листинг 4.5).

Листинг 4.5

var str = "Hello World"

Для выполнения операции инициализации значения используется оператор присваивания, или, иначе, — оператор инициализации, обозначаемый как знак равенства (=).

Оператор инициализации (присваивания) (=) — это особый бинарный оператор. Он используется в типовом выражении a = b, инициализируя значение объекта a значением объекта b. В данном примере объекту str инициализируется текстовое значение "Hello World".

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

Левая и правая части оператора присваивания должны быть однотипными (то есть иметь одинаковый тип, предназначаться для хранения данных одного и того же типа). В данном случае строка «Hello World» — это данные строкового типа. Создаваемая переменная str также имеет строковый тип, он определяется автоматически за счет инициализируемого значения. Об определении типа значения поговорим чуть позже.

4.5. Переменные и константы

В предыдущем листинге для объявления хранилища данных str используется оператор var.

Всего в Swift выделяют два типа хранилищ данных:

• переменные, объявляемые с помощью ключевого слова var;

• константы, объявляемые с помощью ключевого слова let.

Любое хранилище, неважно, какого типа, имеет три важнейших свойства:

1) имя, по которому можно проинициализировать новое или получить записанное ранее значение;

2) тип значения, определяющий, какие данные могут храниться в данном хранилище;

3) значение, которое в данный момент находится в хранилище.

ПРИМЕЧАНИЕ Хранилище всегда должно иметь значение. Оно должно быть проинициализировано в одном выражении с объявлением этого хранилища (в качестве примера смотрите листинг 4.5). Если вы объявите хранилище, то определите тип его значения, но не передадите само значение, Xcode сообщит об ошибке (рис. 4.8).

Рис. 4.8. Сообщение об ошибке при создании хранилища без значения

Ключевое слово String после имени хранилища указывает на то, что оно предназначено для хранения строковых данных. Позже мы подробно разберем как и зачем определяется тип данных хранилища.

Рассмотрим каждый тип хранилища подробнее.

Переменные

Одно из важнейших базовых понятий в любом языке программирования — переменная.

Переменная — это именованная область памяти (хранилище данных), в которой должно быть записано значение определенного типа данных. Значение переменной может быть многократно изменено разработчиком в процессе работы программы. В качестве примера можно привести переменную, которая хранит текущую секунду. Ее значение должно меняться ежесекундно.

Для объявления переменной в Swift используется оператор var.

Синтаксис

var имяПеременной = значение_переменной

После оператора var указывается имя объявляемой переменной. После имени указывается оператор присваивания и инициализируемое значение.

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

Рассмотрим пример объявления переменной (листинг 4.6).

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

Листинг 4.6

var age = 21

В данном примере создается переменная с именем age и значением 21. То есть код можно прочитать следующим образом: «Объявить переменную с именем age и присвоить ей целочисленное значение 21».

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

Изменить значение переменной можно, инициализировав ей новое значение. Повторно использовать оператор var в этом случае не требуется (листинг 4.7).

ПРИМЕЧАНИЕ Оператор var используется единожды для каждой переменной только при ее объявлении.

Будьте внимательны: во время инициализации нового значения старое уничтожается.

Листинг 4.7

var age = 21

age = 22

В результате выполнения кода в переменной age будет храниться значение 22. Обратите внимание, что в области результатов будет выведено два значения: старое (21) и новое (22). Старое — напротив первой строки кода, новое — напротив второй (рис. 4.9).

Рис. 4.9. Отображение значения переменной в области результатов

ПРИМЕЧАНИЕ Уже на протяжении нескольких лет при работе в Xcode Playground разработчики встречаются с тем, что написанный код зачастую не выполняется, результаты не отображаются в области результатов Xcode, программа будто зависает. По умолчанию стоит режим автоматического выполнения кода, сразу после его написания. К сожалению, он периодически дает сбой. В этом случае вы можете перейти в режим выполнения кода по запросу. Для этого нажмите и удерживайте кнопку мыши на символе «квадрат» в нижней части Xcode, пока не появится всплывающее окно с двумя вариантами. Выберите Manually Run (рис. 4.10).

Рис. 4.10. Выбор режима выполнения кода

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

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

Иногда даже после многократных перезапусков среды разработки код все равно не будет выполняться. Причиной этому может быть зависший симулятор. Для решения этой проблемы вы можете попробовать принудительно закрыть его: откройте «ПрограммыУтилитыМониторинг системы», после чего найдите и завершите процесс com.apple.CoreSimulator.CoreSimulatorService.

Рис. 4.11. Принудительный запуск кода на выполнение

Помимо этого, вы можете изменить платформу playground-проекта с iOS на macOS. Для этого нажмите кнопку «Hide or Show the Inspector», расположенную в провом верхнем углу, и в поле Platform выберите необходимый пункт (рис. 4.12). В этом случае вам придется заменить строку import UIKit на import Foundation, так как модуль UIKit существует только для iOS-симулятора.

Рис. 4.12. Смена платформы Xcode Playground

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

Область результатов Xcode Playground позволяет узнать текущее значение любого параметра. Для этого достаточно лишь написать его имя, после чего актуальное значение появится в области результатов. Определим текущее значение переменной, тем самым убедившись, что оно действительно сменилось. Для этого напишите в следующей строке имя переменной и посмотрите на область результатов (рис. 4.13).

Рис. 4.13. Уточнение значения переменной

Константы

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

Синтаксис

let имяКонстанты = значение_константы

После оператора let указывается имя создаваемой константы, с помощью которого будет производиться обращение к записанному в константе значению. Далее, после имени и оператора присваивания, следует инициализируемое значение.

Рассмотрим пример объявления константы (листинг 4.8).

Листинг 4.8

let name = "Vasiliy"

В результате выполнения кода будет объявлена константа name, содержащая строку «Vasiliy». Данное значение невозможно изменить в будущем. При попытке сделать это Xcode сообщит об ошибке (рис. 4.14).

Рис. 4.14. Ошибка при изменении значения константы

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

На рис. 4.14 был показан пример ошибки. Для того чтобы ознакомиться с рекомендациями, необходимо нажать на кружок слева от сообщения об ошибке. После нажатия на кнопку Fix ошибка будет исправлена. В данном примере рекомендовано изменить оператор let на var (рис. 4.5).

Рис. 4.15. Автоматическое исправление ошибки

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

Оператор let так же, как и var, необходимо использовать единожды для каждого хранилища (только при его объявлении).

При необходимости объявить несколько параметров вы можете использовать один оператор, var или let, после чего через запятую указать имена и инициализируемые значения (листинг 4.9).

Листинг 4.9

let friend1 = "John", friend2 = "Helga"

var age1 = 54, age2 = 25

Разумное использование переменных и констант привносит удобство и логичность в Swift.

4.5. Инициализация копированием

Инициализацию значения любых параметров (переменных и констант) можно проводить, указывая в правой части выражения не только конкретное значение, но и имя другого параметра (листинг 4.10).

Листинг 4.10

var myAge = 40

var yourAge = myAge

yourAge

Переменная yourAge имеет значение 40, что соответствует значению переменной myAge.

Стоит отметить, что таким образом вы создаете копию исходного значения, то есть в результате операции будут объявлено две независимые переменные с двумя независимыми значениями. Изменение одного из них не повлияет на другое.

Такой тип параметров, когда передача значения происходит копированием, называется value type (значимые типы). Помимо этого, существует передача ссылки на значение (reference type, или ссылочные типы), когда все переменные содержат в себе ссылку на одно и то же значение, хранящееся в памяти. При этом изменение значения через любую из переменных отразится и на всех ее копиях-ссылках.

Подробнее об этом поговорим в следующих главах.

4.6. Правила именования переменных и констант

При написании программ на Swift вы можете создавать параметры с любыми именами, при этом использовать произвольные Unicode-символы и эмодзи. Существуют правила, которых необходимо придерживаться при именовании параметров:

1. Переменные и константы следует именовать в верблюжьем регистре (camel case). Это значит, что при наименовании используются только латинские символы (без подчеркиваний, тире, математических формул и т.д.) и каждое значимое слово (кроме первого) в имени начинается с прописной (заглавной) буквы. Например: myBestText, theBestCountry, highScore.

Хотя их имена и могут содержать любые Unicode-символы (лис­тинг 4.11), использование таких имен только мешает читабельности кода.

Листинг 4.11

var dØw = "Значение переменной с невоспроизводимым именем"

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

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

Xcode отобразит ошибку при попытке дать параметру имя, соответствующее какому-либо ключевому слову. Если вам все же требуется сделать это, то следует написать его в апострофах (`). Я настоятельно рекомендую избегать этого, чтобы не нарушать читабельность кода.

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

Листинг 4.12

var `var` = "Пример переменной с именем var"

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

var nou — пример плохого имени переменной.

var userName — пример хорошего имени переменной.

var nameOfUserOfMyBestApplicationInTheWorld — пример плохого имени переменной.

4.7. Возможности автодополнения и кодовые сниппеты

Уверен, что вы обратили внимание на то, что при вводе кода появляется всплывающее окно, содержащее различные записи (рис. 4.16). Данная функция Xcode называется автодополнением, мы упоминали о ней ранее. С ее помощью вы можете значительно сократить время написания кода, выбирая наиболее подходящий из предложенных вариант.

Рис. 4.16. Окно автодополнения в Xcode

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

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

Так, к примеру, если в новой строчке кода ввести ключевое слово var, то вы увидите соответствующий сниппет (обозначенный как две фигурные скобки) (рис. 4.17).

Рис. 4.17. Сниппет оператора var

Щелкнув по нему (или нажав на клавишу Enter), вы сможете с легкостью создать новую переменную, заполняя выделенные серым участки сниппета и перескакивая между ними с помощью клавиши Tab.

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

Рис. 4.18. Библиотека кодовых сниппетов

4.8. Глобальные и локальные объекты

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

ПРИМЕЧАНИЕ Удивительно, но переменные и константы могут содержать в своем составе другие переменные и константы! Это более глубокий уровень применения языка Swift, и мы познакомимся с ним в дальнейшем.

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

Область видимости делит объекты на два типа.

• Глобальные объекты — это объекты, доступные в любой точке программы.

• Локальные объекты — это объекты, доступные в пределах родительского объекта.

Рассмотрим следующий пример: у вас есть программа, в которой существуют несколько объектов. У каждого объекта есть собственное имя, по которому он доступен (рис. 4.19).

Объекты Object-1 и Object-2 объявлены непосредственно в корне программы. Такие объекты называются глобальными, и они доступны в любой точке программного кода.

Объект Object-2 имеет вложенный объект Object-3, который является локальным: он объявлен в контексте Object-2 и доступен только в его пределах. Таким образом, попытка получить доступ к Object-3 из Object-1 завершится ошибкой. Но при этом внутри Object-3 будут доступны и Object-1, и Object-2.

Рассмотрим другой вариант организации объектов (рис. 4.20).

Каждый из корневых объектов имеет по одному вложенному. Особенность данной иерархии в том, что локальные объекты имеют точно такие же имена, как и глобальные. В таком случае ошибки не происходит и локальный объект перекрывает глобальный, то есть, обращаясь к Object-2 внутри Object-1, вы обращаетесь к локальному объекту, а не к глобальному.

Рис. 4.19. Вариант иерархии объектов внутри программы

Рис. 4.20. Еще один вариант иерархии объектов

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

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

Время жизни локальных объектов равно времени жизни их родительских объектов.

4.9. Комментарии

Классические комментарии

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

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

На рис. 4.21 приведен пример комментариев. По умолчанию они выделяются серым цветом.

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

Рис. 4.21. Пример комментариев на странице с кодом

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

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

Swift позволяет использовать однострочные и многострочные комментарии.

Однострочные комментарии пишутся с помощью двойного слеша (// комментарий) перед текстом комментария, в то время как многострочные обрамляются звездочками со слешем с обеих сторон (/* комментарий */). Пример комментариев приведен в листинге 4.13.

Листинг 4.13

// это — однострочный комментарий

/* это -

многострочный

комментарий */

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

Markdown-комментарии

Xcode Playground поддерживает markdown-комментарии — особый вид комментариев, позволяющий применять форматирование. Таким образом ваш playground-проект может превратиться в настоящий обу­чающий материал.

Markdown-комментарии должны начинаться с двоеного слеша и двоеточия (//:), после которых следует текст комментария. Несколько примеров неформатированных комментариев приведены на рис. 4.22.

Рис. 4.22. Неформатированные markdown-комментарии

Включить форматирование комментариев, при котором все markdown-комментарии отобразятся в красивом и удобном для чтения стиле, можно, выбрав в меню Xcode пункт EditorShow Rendered Markup. Результат приведен на рис. 4.23.

Рис. 4.23. Форматированные markdown-комментарии

Вернуть markdown-комментарии к прежнему неформатированному виду можно, выбрав в меню пункт Editor Show Raw Markup.

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

4.10. Точка с запятой

Некоторые популярные языки программирования требуют завершать каждую строчку кода символом «точка с запятой» (;). Swift в этом отношении пошел по другому пути. Обратите внимание, что ни в одном из предыдущих листингов данный символ не используется. Это связано с тем, что для этого языка нет такой необходимости. Строчка считается завершенной, когда в ее конце присутствует (невидимый) символ переноса, то есть когда вы нажали Enter.

Единственным исключением является ситуация, когда в одной строчке необходимо написать сразу несколько выражений (листинг 4.14).

Листинг 4.14

// одно выражение в строке — точка с запятой не нужна

var number = 18

// несколько выражений в строке — точка с запятой нужна

number = 55; var userName = "Alex"

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

4.11. Отладочная консоль и функция print(_:)

Консоль

Консоль — это интерфейс командной строки, который позволяет отображать текстовые данные. Если у вас есть опыт работы с компьютером (в любой из существующих ОС), то вы наверняка неоднократно сталкивались с консольными приложениями (рис. 4.24).

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

Рис. 4.24. Пример консоли в различных операционных системах

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

Вернитесь в Xcode Playground. Обратите внимание на три кнопки, расположенные в ряд в верхнем правом углу окна Xcode (рис. 4.25).

Рис. 4.25. Функциональные кнопки в Xcode Playground

Каждая из кнопок позволяет отобразить дополнительные панели, расширяющие возможности среды разработки. Активные кнопки выделены синим цветом, неактивные — серым. После нажатия центральной кнопки отобразится отладочная консоль Xcode Playground (рис. 4.26).

Рис. 4.26. Отладочная консоль Xcode Playground

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

ПРИМЕЧАНИЕ Отладка — это этап разработки программы, на котором обнаруживаются и устраняются ошибки.

Вывод текстовой информации

Как вы могли видеть ранее, в Xcode при работе с Playground значения переменных и констант отображаются в области результатов. Напомню, что для этого необходимо написать любое выражение либо просто имя любого параметра.

В редакторе кода необходимо всего лишь написать имя объявленной и проинициализированной ранее переменной или константы (лис­тинг 4.15).

Листинг 4.15

let name = "Dolf" // в области результатов отобразится "Dolf"

var size = 5 // в области результатов отобразится 5

name // в области результатов отобразится "Dolf"

size+3 // в области результатов отобразится 8

Данный механизм контроля значений очень полезен, тем не менее не всегда применим (в частности, в реальных Xcode-проектах при создании приложений никакой области результатов нет, интерфейс среды разработки приложений отличается от интерфейса Xcode Playground).

Существует иной способ вывода информации, в том числе значений переменных. Будь то Playground или полноценное приложение для iOS или macOS, произвольные данные можно отобразить на отладочной консоли.

Вывод на консоль осуществляется с помощью глобальной функции print(_:).

Синтаксис

print(сообщение)

• сообщение — текстовое сообщение, выводимое на консоль.

Функция выводит на отладочную консоль текстовое сообщение.

Пример

print("Текстовое сообщение")

Консоль

Текстовое сообщение

Рис. 4.27. Пример вывода информации на отладочную консоль

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

Функции позволяют избежать дублирования кода: они группируют часто используемый код с целью многократного обращения к нему посредством уникального имени.

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

Некоторые функции построены таким образом, что при их вызове можно (или даже нужно) передать входные данные, которые будут использованы функцией внутри нее (как у функции print(_:) ). Такие данные называются входными параметрами, или аргументами функции. Они указываются в скобках после имени вызываемой функции. Пример вызовов функций с передачей входных параметров приведен в листинге 4.16.

Листинг 4.16

// входной параметр с именем

anotherFunction(name: "Bazil")

// безымянный входной параметр

print("Это тоже входной параметр")

В данном коде происходит вызов функции с именем anotherFunction (такой функции не существует, это лишь пример), которая принимает входной аргумент name с текстовым значением «Bazil».

ПРИМЕЧАНИЕ Если вы напишете данный код в своем playground, то Xcode сообщит вам об ошибке, так как такой функции еще не существует, она пока не объявлена (рис. 4.28).

Рис. 4.28. Ошибка при вызове несуществующей функции

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

Рис. 4.29. Панель с информацией об ошибках

Вы можете закрыть ее с помощью левой кнопки.

ПРИМЕЧАНИЕ При описании функций в некоторых случаях указывается на необходимость передачи входных параметров путем указания имен аргументов внутри скобок, после каждого из которых пишется двоеточие (например, anotherFunction(name:) или someFunction(a:b:)).

Если входной параметр не имеет имени, то вместо его имени ставится нижнее подчеркивание (примером может служить упомянутая выше функция print(_:)).

Таким образом, указание goodFunction(_:text:) говорит о том, что вы можете использовать функцию с именем goodFunction, которой необходимо передать два входных параметра: первый не имеет имени, а второй должен быть передан с именем text.

Пример вызова функции goodFunction (_:text:) приведен ниже.

goodFunction(21, text:"Hello!")

Вернемся к рассмотрению функции print(_:) (листинг 4.17).

Листинг 4.17

// вывод информации на отладочную консоль

print("Привет, ученик!")

Консоль:

Привет, ученик!

Приведенный код выводит на отладочную консоль текст, переданный в функцию print(_:) (рис. 4.30).

Обратите внимание, что выводимый на консоль текст дублируется и в области вывода результатов, но при этом в конце добавляется символ переноса строки (\n).

Рис. 4.30. Вывод текста на отладочную консоль

Функция print(_:) может принимать на вход не только текст, но и произвольный параметр (переменную или константу), как показано в листинге 4.18.

Листинг 4.18

var foo = "Текст для консоли"

print(foo)

Консоль:

Текст для консоли

Созданная переменная foo передается в функцию print(_:) в качестве входного аргумента (входного параметра), ее значение выводится на консоль.

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

Листинг 4.19

var bar = "Swift"

print("Я изучаю \(bar)")

Консоль:

Я изучаю Swift

Вы будете использовать функцию print(_:)  довольно часто, особенно в ходе обучения разработке на Swift. Это связано с тем, что она предоставляет отличный способ контроля текущего значения параметров, а также один из самых простых способов поиска ошибок в алгоритме работы программы.

Назад: Часть II. Базовые возможности Swift
Дальше: 5. Фундаментальные типы данных