Создать Playground
Запустим Xcode и создадим Playground. Назовем его “BasicSwift”:
File → New → Playground…
⌥⇧⌘N
Swift Playground – это такой тип файлов, который представляет из себя игровую площадку для ваших экспериментов с кодом Swift. Результат исполнения каждой строчки кода вы можете наблюдать в боковой панели (Sidebar).
Переменные, константы, типы
Переменные обозначаются с помощью ключевого слова var
var hello = "Hello Proglib"
Чтобы объявить константу используется ключевое слово let
let brandName = "Proglib"
Swift – это статистический типизированный язык, а это значит, что мы должно явно задать тип каждой переменной во время компиляции .
Указывать тип переменной необязательно. Компилятор Swift автоматически его определит. Эта особенность называется интерференцией типов(type inference).
Swift предлагает следующие базовые типы: Int или UInt , Double , Float , String , Character , Bool , Tuples , Optional .
Множество типов фундаментально и чаще всего используется для объявления переменных. Забегая вперед скажу, что вы также можете создавать и свои собственные типы.
Мы не будет детально разбирать их все! Посвятим этой теме следующую 30-ти минутку.
Укажем тип нашей константы .
let brandName: String = "Proglib"
Больше полезной информации вы можете найти на нашем телеграм-канале «Библиотека мобильного разработчика». Интересно, перейти к каналу
Интерполяция строк
Давайте теперь выведем имя бренда в консоль при помощи функции print()
.
print(brandName)
Интерполяция – это способ объединить переменные и константы внутри строки.
Теперь присвоим переменной hello
новое значение, и выведем в консоль.
hello = "Hello (brandName)" print(hello)
Вот еще пример:
let name = "Ivan" var age: UInt8 = 30 print("(hello). My name is (name). I am (age)")
Базовые операторы
Здесь все интуитивно. Предлагаю вам поэкспериментировать с ними самостоятельно и посмотреть на результаты.
Арифметические операторы
+
сложение
—
вычитание
/
деление
%
деление по модулю
var a = 1, b = 2 var result = a + b // etc
Операторы присвоения
= , +=, -=, /=, %=
var h = 10 h += 1 h /= 2 h %= 2 // etc
Операторы сравнения
Операторы сравнения в качестве результата возвращают значения типа Bool
==, ≠, >, <, ≥, ≤
let condition = 2 > 3 let condition2 = 1 != 0 let resultCondition = condition == condition2 // etc
Логические операторы
Логические операторы используют для комбинирования или инверсии булевых значений.
Рассмотрим на примере:
// логическое И print(true && true) // true print(true && false) // false // логическое ИЛИ print(true || false) // true // логическое НЕ – инвертирует булево значение print(!true) // false
Это еще не все операторы, которые существуют в Swift. Остальные мы рассмотрим в контексте целей их предназначения.
Коллекции
Swift предлагает нам три основных типа коллекций: Array(Массивы) , Dictionary(Словари) и Set(Множества) . Сейчас мы рассмотрим первые два.
Array
Используйте квадратные скобки [] , чтобы создавать массивы(Array) и словари(Dictionary) .
Получить доступ к элементам массива можно написав индекс внутри скобок .
let digits: [UInt8] = [0, 1, 2, 3, 4, 5, 6, 7, 8 ,9] print(digits[3])
Попробуйте изменить значение в массиве digits
. Что произойдет?
digits[0] = 1
🪲 Cannot assign through subscript: ‘digits’ is a ‘let’ constant
Поскольку мы объявили массив как константу , то и все его значения становится не изменчивыми (immutable) , как и его размер . А если мы объявим массив как переменную , то он будет изменчивым (mutable) . Такое свойство называют изменчивостью коллекций (mutability of collection).
Это утверждение справедливо и для Словарей .
// mutable var numbers = [50, 10, 20, 34, 45] print(numbers[0]) numbers[0] = numbers[0] + 1
Dictionary<Key, Value>
Создадим словарь sunSystemData
, в который добавим данные о солнечной системе.
Пусть ключами (key) данного словаря будут номера объектов солнечной системы, а значениями (value) названия объектов. Поскольку звезда рождается первой, то будем считать, что ключ со значением 0
всегда указывает на звезду. Остальные объекты следуют в порядке по отношению к звезде.
var sunSystemData = [ 0: "Sun", 1:"Mercury", 2:"Venus", 3:"Earth", 4:"Mars", 5:"Jupiter", 6:"Saturn", 7:"Uranus", 8:"Neptune"]
Мы не указали типы для словаря явно. Вы можете проверить как их определил Swift, используя функцию стандартной библиотеки Swift (Swift Standard Library) type(of: T)
.
type(of: sunSystemData) // Dictionary<Int, String>
Обратиться к элементу словаря можно, написав ключ внутри скобок . Результат будет содержать значение опционального типа (Optional) , а если по заданному ключу (в скобках) нет соответствующего элемента, то получим nil
.
nil
в Swift означает отсутствие значения .
Получим нашу родную планету и выведем ее в консоль.
var homePlanet = sunSystemData[3] print("My home is (homePlanet)")
Когда мы попытались вывести переменную в консоль, то получили предупреждение!
🪲 String interpolation produces a debug description for an optional value; did you mean to make this explicit?
Давайте посмотрим какой именно тип приняла переменная.
type(of: homePlanet) // Optional<String>
Чтобы избавиться от предупреждения в интерполяции строки, нам необходимо указать что именно мы выводим. Сделать это можно при помощи оператора as
. В этом случаи мы увидим напечатанный nil
, когда значение отсутствует. Попробуйте обратиться к элементу с ключом 0
.
print("My home is (sunSystem[0] as String?)") // My home is nil print("My home is (homePlanet as String?)") // My home is Earth
Другим решением может быть присвоение переменной значения по умолчанию.
Сделать это мы можем при помощи оператора объединения по nil
– ??
var homePlanet = sunSystem[3] ?? "Unknown planet" print("My home is (homePlanet)") // My home is Earth
Пока опустим темы об опциональных типах и приведении типов(type casting).
В следующих статьях я расскажу о них подробней.
Продолжим!
Кстати, если вы считаете, что Плутон это планета, то можете добавить её самостоятельно!
sunSystem[9] = "Pluto"
Чем отличаются массивы от словарей?
Массивы хранят множество значений определенного типа в упорядоченном списке . Любое значение может присутствовать несколько раз в списке.
Словари хранят множество значение определенного типа , где каждое значение связано с уникальным ключом , который идентифицирует это значение внутри словаря. Элементы в словаре не имеют определенного порядка , как в массивах.
Используйте словари , как вы их используете в реальном мире. Когда вам необходимо искать значения на основе их идентификатора (ключа).
Например:
var HierarchyOfNumbers: [Character:String] = [ "N":"Natural Numbers" "Z":"Integers" "Q":"Rational Numbers" "R":"Real Numbers" "C":"Complex Numbers" ]
Управление потоком
Часто необходимо выполнять различный код базирующийся на определенных условий (conditions) .
Если вам необходимо написать различную логику, которая зависит от определенных условий, тогда используйте условные инструкции if
, switch
. Инструкцияif
хорошо подходит для простых сравнений, и нескольких вариантов исходов.
Инструкция switch
подходит для более сложных условий. Лучше использовать ее, когда вам необходимо выбрать из множества вариантов альтернатив, основываясь на каком-либо значении, т.е. выполнить код соответствующий определенному шаблону.
Когда вам необходимо многократно повторить какие либо инструкции, используйте циклы: for-in,
while
.
If…else
Инструкция if
бывает трех форм.
Традиционное ее представление выглядит так:
var condition = true if condition { // } else { // }
В зависимости от условия , мы попадаем в определенные блоки кода. Когда условие истинно(true) , выполняется блок следующий за if
, а когда ложно(false) , выполняется блок следующий за else
.
Например, вы решили, что Плутон планета? Сейчас узнаем!
var isPluto = sunSystemData[9] != nil if isPluto { print("Pluto is planet") } else { print("Pluto is not planet") }
if…
Мы можем опустить блок else
, когда нам необходимо выполнить только одно условие.
Рассмотрим такой случай. У нас есть данные, и мы не хотим перезаписать значение. Тогда необходимо проверить наличие данных, и только после добавить значение.
var key = 0, value = "Sun" var isExists = sunSystemData[key] != nil // false if !isExists { // true sunSystemData[key] = value }
if…else if…else
Также мы можем добавить условия следующее за else
.
var value = 0 if value > 0 { print("(value)") } else if value == 0 { print(value) } else { print(value) }
Вы можете комбинировать if else
.
Например:
var a = 0, b = 3, c = 1 if a > b { print(a - b) } else if b > a { print(b - a) } else if c < a { print(a - c) } else { print(a + b + c) }
switch
В самой простой форме switch
выглядит так:
var value = "R2-D2" switch value { case "R2-D2": print("Take him!") case "C-3PO": print("Take him!") default: print("These aren't the droids you're looking for.") }
Ключевое слово case
определяет возможный случай (шаблон) , с которым сравнивается значение value
. Затем исполняется соответствующий блок кода на основе первого успешно совпавшего шаблона. В случаи если совпадений не найдено, исполняется блок default
, который всегда следует после остальных случаев. Условие default
гарантирует что наша конструкция полная и законченная.
Поменяйте значение value
, и посмотрите, какой блок кода исполнился.
for-in
Цикл for-in
упрощает перебор по последовательностям, т.к. массивы, словари, строки.
Синтаксис for-in
выглядит так:
for value in sequence{ // }
Цикл for-in
исполняет инструкции определенное количества раз, пока мы не достигнем конца последовательности.
value
– элемент последовательности на каждой итерации(iteration, повторении).
Рассмотрим пример перебора значений массива и словаря .
for digit in digits { print(digit) } for (key, value) in sunSystemData { print("Key:(key) Value:(value)") }
while
while
имеет две формы.
Первая из них начинается с вычисления условия . Такой цикл можно рассматривать как повторяющаяся инструкция if
.
var condition = true; while (condition) { // тело цикла }
Например, мы хотим пройти 10 000 шагов.
var stepGoal = 10_000 var mySteps = 0 while mySteps < 10_000 { mySteps += 1 }
Цикл будет работать пока условие mySteps < 10_000
принимает булево значение true
.
Внутри тела цикла мы увеличиваем переменную mySteps
на один шаг.
Когда условие принимает значение false
, то цикл останавливается.
Расчет факториала числа.
var counter = 5 var factorial = 1 // начальное значение while counter > 0 { factorial *= counter counter -= 1 } print(factorial)
Здесь я вам предлагаю разобраться самостоятельно 😉
Вторая форма исполняет тело цикла прежде , чем вычислит условие . Следовательно, мы можем быть уверены что тело цикла выполняется один раз.
В остальном repeat-while
ведет себя идентично while
.
var condition = true repeat { // тело цикла } while (condition)
Также цикл while
используется, когда нам заранее неизвестно число итераций последовательности. В отличии от цикла for-in
.
Функции
В Swift есть два типа функций:
Пользовательские(User-defined Function) и функции стандартной библиотеки ( Standard Library Functions) .
Функции помогают организовывать код, разбив его на более мелкие части, что делает код более легким для понимания и переиспользования. Мы уже использовали функции стандартной библиотеки, такие как print()
и type()
. Рассмотрим, как создаются пользовательские функции.
Функция – блок кода, который выполняет конкретную задачу.
Каждая функция имеет уникальное имя , которое является ее идентификатором .
func functionName(parameters) -> returnType { // тело функии }
Объявить функцию можно при помощи ключевого слова func
.
За ним следует имя функции – functionName
.
В скобках указываются параметры(parameters) функции.
Параметр – это значение определенного типа, принимаемое функцией.
returnType
– указывает, какого типа значение возвращает функция
Чтобы исполнить функцию, ее необходимо вызвать (как мы уже делали это с print()
).
// вызов функции functionName()
Функции без параметров
Функции в которые мы не передаем параметры, называются функциями без параметров . Например, приветствие, которое мы написали в самом начале может быть организовано в виде функции.
func greetings() { print("Hello Proglib!") } greetings() print("Done!")
Мы объявили функцию с именем greetings()
, которая просто печатает "Hello Proglib!"
в консоли. Она не имеет параметров и возвращаемого значения . При вызове функции управление программой переходит к определению функции . Затем исполняется код, который содержится внутри тела функции:
print("Hello Proglib!")
Как только функция завершится, управление потоком переходит к следующей инструкции после вызова функции.
print("Done!")
Функции с параметрами
Функции, в которым мы передаем аргументы, называются функциями с параметрами. Если мы хотим, чтобы функция возвращала значение, нужно использовать оператор return
.
Например, разница между двумя значениями:
func difference(a: Int, b: Int) -> Int { return a - b } var result = difference(a: 3, b: 2) print(result)
Мы объявили функцию с именем difference
, которая принимает два параметра типа Int
и возвращает значение типа → Int
. При вызове функции, мы передаем параметры в круглых скобках (a: 3, b: 2)
.
Каждый параметр функции состоит из метки аргумента и имени параметра . Имена параметров используются при реализации функции.
func difference(of a: Int, less b: Int) -> Int { return a - b }
Метка аргумента используется при вызове функции.
difference(of: 1, less: 2)
По умолчанию параметры используют свое имя параметра в качестве метки аргумента (как в первом примере).
Если вам не нужна метка для аргумента, то напишите _
вместо конкретного названия метки для аргумента.
func difference(_ x: Int, _ y: Int) -> Int { return x - y } difference(3, 4)
Мы можем опустить оператор return
, когда тело функции является одним выражением.
func difference(a: Int, b: Int) -> Int { a - b }
Заключение
Мы познакомились с фундаментальным синтаксисом языка программирования Swift. Рассмотрели основные операторы, научились объявлять переменные и объединять код в функции. В следующие полчаса разберем каждую тему более глубоко. На сегодня все! Playground доступен на Github.