Статьи

iOS с нуля с помощью Swift: Swift в двух словах

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

Невозможно охватить основы программирования и изучить Swift в одной или двух статьях. Поэтому я предполагаю, что у вас уже есть опыт программирования. Ruby, PHP или JavaScript являются хорошей отправной точкой для изучения Swift. Если вы пришли из веб-разработки, у вас не должно возникнуть проблем с изучением основ Swift, прочитав следующие две статьи.

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

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

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

На протяжении всей этой серии я буду использовать Xcode 7.1 и Swift 2.1 . Если вы используете более старую версию Xcode, имейте в виду, что вы не будете работать с Swift 2.1. Swift продолжает меняться быстрыми темпами, и синтаксис развивается с каждой итерацией языка. Поэтому я рекомендую использовать Xcode 7.1, который включает Swift 2.1.

В 2014 году Apple представила игровые площадки в составе Xcode 6. Игровые площадки отлично подходят для изучения языка программирования Swift. На игровых площадках вы можете сосредоточиться на написанном коде, а не возиться с настройками проекта, файлами и папками.

Давайте создадим игровую площадку, чтобы начать изучать основы Swift. Запустите Xcode 7.1 и выберите New> Playground … в меню Xcode File . Игровые площадки поддерживают OS X, iOS и TVOS. Установите платформу на iOS и назовите детскую площадку Свифт в двух словах .

Создать игровую площадку

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

Пользовательский интерфейс Playground

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

1
//: Playground — noun: a place where people can play

Строка начинается с двух косых черт, // , указывающих, что эта строка является комментарием и игнорируется компилятором. Комментарии, которые занимают несколько строк, начинаются с /* и заканчиваются */ .

1
2
3
4
5
/*
    This is a longer
    comment spanning
    multiple lines.
*/

Xcode также добавил оператор импорта для инфраструктуры UIKit. UIKit является наиболее важной основой для разработки под iOS. Он определяет строительные блоки, из которых создаются приложения для iOS. В Swift импортировать фреймворк так же просто, как использовать ключевое слово import за которым следует имя фреймворка UIKit .

1
import UIKit

Последняя строка может напоминать некоторым из вас о JavaScript. Мы используем ключевое слово var чтобы объявить переменную str и присвоить ей значение "Hello, playground" . Этот пример сразу показывает ключевую особенность Swift, вывод типа .

1
var str = «Hello, playground»

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

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

1
var str: String = «Hello, playground»

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

Значение константы не может быть изменено

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

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

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

1
2
3
let myBool = true
var notTrue = false
notTrue = true

Числа представлены Int , UInt , Float или Double . Существуют и другие типы данных для хранения числовых значений, но они являются наиболее распространенными. Эти типы данных похожи на те, которые вы найдете в других языках программирования.

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

Преобразование типов

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

Преобразование числа

Даже при том, что может показаться, что мы разыгрываем Float , это не то, что происходит. Мы создаем или инициализируем Float используя значение, хранящееся в.

Существует два способа создания переменной или константы: буквальный синтаксис и синтаксис инициализатора . Константы a и b были созданы с использованием буквального синтаксиса. Переменная str мы обсуждали ранее, является еще одним примером буквального синтаксиса.

Чтобы создать Float из значения, хранящегося в a , мы используем синтаксис инициализатора. Мы создаем Float , используя имя типа, Float , за которым следуют две скобки, передавая в качестве параметра.

Мы уже встречали некоторые строки в этом уроке. Строка — это не более чем последовательность символов. Фактически, можно получить доступ к коллекции символов, как показано в примере ниже.

1
2
let city = «Brussels»
let chars = city.characters

В приведенном выше примере мы используем строковый литерал. В следующем примере показано, как использовать инициализатор типа String . Синтаксис идентичен тому, что мы видели в одном из предыдущих примеров о преобразовании чисел и типов.

1
let country = String(«Belgium»)

Стандартная библиотека Swift определяет три общих типа коллекций: Array , Dictionary и Set . Эти типы коллекций требуют небольшого объяснения, если вы знакомы с Objective-C или любым другим языком программирования. В некоторых языках словари известны как хеши, а массивы — как списки. Идея, однако, та же самая.

1
2
3
let myArray = [1, 2, 3, 4, 5]
let myDictionary = [«One»: 1, «Two»: 2, «Three»: 3]
let mySet = Set([«One», «Two», «Three», «Four», «Five»])

Массив и словарь инициализируются с использованием буквального синтаксиса. Поскольку тип Set не имеет буквального синтаксиса, мы используем синтаксис инициализатора для создания константы mySet .

Я уже упоминал, что Swift является строго типизированным языком, и это также имеет последствия для типов коллекций. Следующий пример иллюстрирует это. Начнем с создания переменной arr1 типа [Int] . Это означает, что arr1 может содержать только значения типа Int .

Типы коллекций

Второе и третье утверждение подтверждают это. Добавление целого числа работает нормально, но добавление строки приводит к ошибке компилятора. Компилятор пытается преобразовать "Two" в Int , но не может этого сделать. Результатом является ошибка.

Следующий пример сделает вещи еще более запутанными. Почему компилятор не жалуется на массив, содержащий значения разных типов? Причина может вас удивить. Константа arr2 имеет тип [AnyObject] .

1
let arr2 = [1, 2, 3, «Four», «Five»]

Стандартная библиотека Swift определяет два специальных типа, Any и AnyObject . Тип Any может представлять любой тип, а тип AnyObject может представлять любой класс или структуру. Если вы запутались, то это совершенно нормально. Swift был разработан для AnyObject типизации, и кажется, что Any и AnyObject подрывают безопасность типов Swift.

Причиной введения Any и AnyObject является прежде всего причина совместимости. Я уже упоминал, что большинство фреймворков, используемых для разработки Какао, написаны на C и Objective-C. Objective-C определяет тип id , который представляет любой объект. Чтобы обеспечить совместную работу сред Swift и Cocoa, стандартная библиотека Swift представила типы Any и AnyObject . Мы узнаем больше об этом, когда начнем работать с фреймворками Cocoa.

Если вы знакомы с объектно-ориентированным программированием, то вы уже должны быть знакомы с классами. Занятия в Swift довольно обычные. Взгляните на следующий пример, в котором мы определяем класс Boat с двумя свойствами: speed и lifeboats и метод deployLifeboats() .

01
02
03
04
05
06
07
08
09
10
class Boat {
 
    var speed: Float = 0
    var lifeboats: Int = 2
     
    func deployLifeboats() {
        // …
    }
 
}

Инициализация и изменение экземпляра класса Boat просты, как вы можете видеть ниже. Вызов метода для экземпляра также не волшебен. Основы классов Swift легко понять. Правильно?

1
2
3
4
5
6
var boat = Boat()
 
boat.speed = 10.5
boat.lifeboats++
 
boat.deployLifeboats()

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

01
02
03
04
05
06
07
08
09
10
struct Ship {
 
    var speed: Float = 0
    var lifeboats: Int = 2
     
    func deployLifeboats() {
        // …
    }
 
}

В следующем примере показано наиболее важное различие между классами и структурами Swift.

Разница между классами и структурами в Swift

Этот пример иллюстрирует, что классы передаются по ссылке, а структуры передаются по значению. Что это обозначает? Мы инициализировали экземпляр Boat , присвоили его boat1 и установили его свойство speed в 11.0 . Мы назначили boat1 boat2 . Это означает, что boat2 имеет ссылку на boat1 . И boat1 и boat2 указывают на один и тот же экземпляр Boat . В результате установка свойства speed boat2 также изменяет свойство speed boat1 .

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

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

Например, каждый тип коллекции в Swift является структурой. Каждый тип чисел является структурой. Это важно знать и понимать, особенно если вы пришли из языка, который передает некоторые из этих типов по ссылке, например, Ruby и Objective-C.

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

1
2
3
4
5
6
7
8
9
class Speedboat: Boat {
     
}
 
var speedboat = Speedboat()
 
speedboat.speed = 100.0
speedboat.lifeboats = 0
speedboat.deployLifeboats()

Поскольку Boat является родительским классом Speedboat , Speedboat наследует свойства и методы, определенные в классе Boat . Пример иллюстрирует это. Несмотря на то что реализация класса myBoat пуста, экземпляр myBoat , myBoat , имеет свойства speed и lifeboats а также метод deployLifeboats() .

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

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

1
2
3
var str: String
 
str.isEmpty

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

Переменная не инициализирована

Во многих языках программирования переменные имеют начальное значение по умолчанию. Например, в Objective-C строка в следующем фрагменте кода равна nil .

1
NSString *newString;

Swift использует опциональные возможности для инкапсуляции важной концепции: переменная или константа имеет значение или нет. Это так просто в Swift. Чтобы объявить переменную или константу необязательной, мы добавляем знак вопроса к типу переменной или константы.

1
var str: String?

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

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

1
2
3
4
5
var str: String?
 
str = «Test»
 
println(str!)

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

Принудительное развертывание необязательного без значения

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

1
2
3
4
5
6
7
var str: String?
 
if str != nil {
    println(str!)
} else {
    println(«str has no value»)
}

Сначала мы проверяем, равен ли str nil прежде чем печатать его содержимое. В этом примере str не имеет значения. Это означает, что он не будет развернут случайно.

Есть более элегантный подход, известный как необязательное связывание. В следующем примере мы присваиваем значение, хранящееся в необязательном порядке, временной константе. Значение необязательного str связано с константой strConst и доступно в предложении if оператора if . Этот подход также работает для операторов while .

1
2
3
4
5
6
7
8
9
var str: String?
 
str = «Test»
 
if let strConst = str {
    println(strConst)
} else {
    println(«str has no value»)
}

Если вы пришли из такого языка, как Objective-C, то вы наверняка знаете, что такое nil . В Objective-C nil — указатель на объект, который не существует. Swift определяет nil немного по-другому, и важно, чтобы вы поняли разницу.

В Swift nil означает отсутствие значения, любое значение. В то время как nil применим только к объектам в Objective-C, в Swift nil может использоваться для любого типа.

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

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

Если у вас есть какие-либо вопросы или комментарии, вы можете оставить их в комментариях ниже или обратиться ко мне в Twitter .