Создание простого приложения с использованием TableView / Habr
Во время проведения WWDC 2019, одним из самым больших и захватывающих моментом был анонс релиза SwiftUI. SwiftUI — это совершенно новый фреймворк, который позволяет проектировать и разрабатывать пользовательские интерфейсы с написанием меньшего количества кода, декларативным способом.В отличие от UIKit, который обычно использовался в сочетании с storyboards, SwiftUI полностью основан на программном коде. Тем не менее, синтаксис очень прост для понимания и проект можно быстро просмотреть с помощью Automatic Preview.
Поскольку SwiftUI использует язык Swift, он позволяет создавать приложения той же сложности с гораздо меньшим количеством кода. Более того, использование SwiftUI автоматически позволяет приложению использовать такие функции, как Dynamic Type, Dark Mode, Localization и Accessibility. Кроме того, он доступен на всех платформах, включая macOS, iOS, iPadOS, watchOS и tvOS. Итак, теперь ваш код пользовательского интерфейса может быть синхронизирован на всех платформах, что дает больше времени для того, чтобы сосредоточиться на второстепенном платформо-зависимом коде.
Об этой статье
Важно, чтобы разработчики узнали, как использовать SwiftUI на более ранних стадиях, поскольку компания Apple в конечном итоге сфокусирует большую часть своего внимания на этом фреймворке. В этой статье мы рассмотрим основы SwiftUI и узнаем, как создавать минимальную навигацию, отображать изображения, текст и списки, посредством создания простого списка контактов, который отобразит всех участников нашей команды. При выборе участника команды, приложение отображает детальную информацию, которая содержит изображение пользователя с его краткой биографией. Давайте начнем!
Запустим Xcode 11. На время написания данной статьи, Xcode 11 все еще находится в бета-версии, поэтому некоторые функции могут работать не так, как ожидалось. В этой статье мы будем использовать Swift 5. Несмотря на то, что продвинутые знания языка Swift не обязательны для данной статьи, все же рекомендуется понимание основ языка.
Примечание редактора: Для предварительного просмотра и взаимодействия с изображениями из Canvas в Xcode, убедитесь, что на Mac установлена MacOS версий 10.15 beta.
Создание нового проекта с использованием SwiftUI
Давайте начнем все сначала, чтобы вы могли сразу увидеть, как запустить приложение SwiftUI. Сначала откройте Xcode и выберите пункт «Create new Xcode project». Для платформы iOS выберите Single View App. Введите название приложению и заполните текстовые поля. Однако следует убедиться, что внизу установлен флажок Use SwiftUI. Если вы не выберите эту опцию, Xcode создаст для вас storyboard файл.
Xcode автоматически создаст для вас файл с именем ContentView.swift, и удивительным будет то, что предварительный просмотр вашего кода, будет отображен с правой стороны, как показано ниже.
Если вы не видите предварительного просмотра, необходимо нажать кнопку Resume в зоне предварительного просмотра. Компиляция проекта займет некоторое время. Будьте терпеливы и дождитесь завершения компиляции.
Теперь давайте посмотрим, как можно изменить эти файлы для создания приложения.
Создание представления в виде списка
Создание представления в виде списка осуществляется в три этапа. Первый — это создание строк в списке. Возможно дизайн похож на UITableView. Для этого необходимо создать ContactRow. Второй этап это передача необходимых данных в список. У меня есть данные, которые уже закодированы, и требуется всего лишь несколько изменений, чтобы связать список с данными. Последний этап — это просто добавление Navigation Bar и встраивание списка в Navigation View. Это довольно просто. Теперь посмотрим, как все это было реализовано в SwiftUI.
Создание списка преподавателей
Как мы видим, в сгенерированном коде имеется компонент Text со значением «Hello World». В редакторе кода изменим значение кода на «Simon Ng».
struct ContentView: View {
var body: some View {
Text("Simon Ng")
}
}
Если все работает верно, справа вы должны увидеть автоматическое обновление. Это эффект мгновенного просмотра, что мы и ожидали.
Давайте добавим в приложении новый элемент Text. Это будет краткое описание участника. Чтобы в приложении добавить новый элемент интерфейса, необходимо нажать кнопку + в правом верхнем углу. Появится новое окно со списком различных вью. Переместим вью с названием Text и поместим его под первоначальный элемент Text, как показано ниже.
Обратите внимание на код слева:
struct ContentView: View {
var body: some View {
VStack {
Text("Simon Ng")
Text("Placeholder")
}
}
}
Можно заметить, что новый элемент Text был добавлен под Text вью с значением Simon Ng. Отличие состоит в том, что теперь это вью, похоже, обернул представление в нечто, называемое VStack. VStack используется для вертикального стека, и он является заменой Auto Layout в SwiftUI. Если у Вас имеется опыт разработки программного обеспечения для watchOS, вы вероятно знаете, что здесь нет никаких ограничений, более того все элементы помещаются в группы. При вертикальном стеке все вью будут расположены вертикально.
Теперь измените текст «Placeholder» на «Founder of AppCoda»
Далее, давайте добавим изображение слева от этого текста. Так как мы хотим расположить представление горизонтально к существующим представлениям, то имеется необходимость обернуть VStack в HStack. Для этого, выполним ⌘+Click на VStack, а затем выберем Embed in HStack. Посмотрим на это ниже:
Данный код должен выглядеть следующим образом:
struct ContentView: View {
var body: some View {
HStack {
VStack {
Text("Simon Ng")
Text("Founder of AppCoda")
}
}
}
}
Значительных изменений пока нету, но сейчас мы добавим изображение. Измените код, чтобы он выглядел следующим образом:
struct ContentView: View {
var body: some View {
HStack {
Image(systemName: "photo")
VStack {
Text("Simon Ng")
Text("Founder of AppCoda")
}
}
}
}
Начиная с iOS 13, Apple представляет новую функцию под названием SFSymbols. SF Symbols, разработанный компанией Apple, представляет собой набор из более чем 1500 символов, которые можно использовать в приложениях. Поскольку они могут легко интегрироваться с системным шрифтом San Francisco, символы автоматически обеспечивают оптическое вертикальное выравнивание с текстом любого размера. Поскольку у нас пока нет изображений наших преподавателей, будем использовать так называемый placeholder.
Теперь сосредоточимся на некоторых незначительных проблемах дизайна. Поскольку имеется необходимость эмуляции внешнего вида UITableRow, давайте выровняем текст по левому краю (т. е. сделаем его главным). Для этого выполним ⌘+Click на VStack и нажмем
Далее увидим изменение в коде. Также код будет изменен в реальном времени для отображения новых изменений.
VStack(alignment: .leading) {
...
}
Теперь, когда второе текстовое представление является заголовком, давайте изменим шрифт. Как и раньше, ⌘+Click на текстовом представлении «Founder of AppCoda» в режиме предварительного просмотра и выбираем Inspect. Изменим шрифт на «Subheadline» и отобразим предварительный просмотр и изменение кода в реальном времени.
Давайте также изменим цвет и установим его на «Серый». Данный код должен выглядеть следующим образом:
struct ContentView: View {
var body: some View {
HStack {
Image(systemName: "photo")
VStack(alignment: .leading) {
Text("Simon Ng")
Text("Founder of AppCoda")
.font(.subheadline)
.color(.gray)
}
}
}
}
Теперь, после окончания проектирования ряда сэмплов, мы подошли к волшебной части. Посмотрите, как легко создать список. Выполним ⌘+Click на HStack и выполним клик на Embed in List. Вуаля! Посмотрите, как код будет автоматически меняться, и пустая область будет отображать 5 красивых новых строк, каждая из которых показывает Simon Ng в качестве члена команды.
Также обязательно обратите внимание, как был создан List в коде. Удалив HStack и заменив его повторяющимся List, было создано табличное представление. Теперь подумайте сколько времени вы сэкономили и на сколько меньше кода написали, избегая все эти UITableViewDataSource, UITableViewDelegate, Auto Layout, реализации для Dark Mode и т. д. Все это само по себе показывает мощь и силу SwiftUI. Тем не менее, мы далеки от завершения. Давайте добавим некоторые реальные данные в новый список.
Подключение данных к списку
Данные, которые нам необходимы, это список участников команды и их биография вместе с папкой со всеми их изображениями. Вы можете скачать необходимые файлы здесь. Вы должны найти 2 файла с именами
После загрузки импортируйте файл с расширением Swift и папку ресурсов в проект Xcode. Чтобы их импортировать, просто перетащите их в навигатор проекта.
В файле Tutor.swift объявляем структура Tutor и приводим ее в соответствие с протоколом Identifiable. Вы поймете, почему это важно позже. Также определяем переменные id, name, headline, bio и imageName. Наконец, добавим некоторые тестовые данные, которые будут использоваться в нашем приложении. В Tutor.xcassets имеются изображения всех участников команды.
Вернитесь к ContentView.swift и измените код следующим образом:
struct ContentView: View { //1 var tutors: [Tutor] = [] var body: some View { List(0..<5) { item in Image(systemName: "photo") VStack(alignment: .leading) { Text("Simon Ng") Text("Founder of AppCoda") .font(.subheadline) .color(.gray) } } } } #if DEBUG struct ContentView_Previews : PreviewProvider { static var previews: some View { //2 ContentView(tutors: testData) } } #endif
Все довольно просто:
- Определим новую переменную с именем tutors, которая является пустым массивом структур Tutor.
- Поскольку мы определяем новую переменную для структуры ContentView, следовательно необходимо также изменить ContentView_Previews, чтобы отобразить это изменение. Установим в testData параметр tutors.
В предварительном просмотре не будет никаких изменений, потому что мы еще не используем тестовые данные. Чтобы отобразить тестовые данные, измените код следующим образом:
struct ContentView: View {
var tutors: [Tutor] = []
var body: some View {
List(tutors) { tutor in
Image(tutor.imageName)
VStack(alignment: .leading) {
Text(tutor.name)
Text(tutor.headline)
.font(.subheadline)
.color(.gray)
}
}
}
}
Убедимся, что ContentView использует tutors для отображения данных на экране.
Вот так! Посмотрите, как изменилось представление.
Изображения отображаются в виде квадрата. Хотелось бы, чтобы они выглядели более округлыми. Давайте посмотрим, как мы можем сделать изображение с закругленными углами. В правом верхнем углу нажмите кнопку + и перейдите на вторую вкладку. Так будет отображен список модификаторов макета, которые вы можете добавлять к изображениям.
Ищите «Corner Radius/Угловой радиус», перетащите его из окна предварительного просмотра и поместите его на изображение. Вы должны увидеть измененный код, и изображения предварительного просмотра будет изменено на следующее.
Тем не менее, радиус закругления в 3 слишком мал. Итак, измените его на 40. Таким образом, получаем красивые скругленные картинки.
Ячейка и список готовы! Далее необходимо отображать детальную информацию, когда пользователь нажимает на ячейку. Давайте начнем работу с создания навигаций.
Создание навигации
Навигационное представление оборачивает уже имеющееся представление в панель навигации и контроллер навигации. Предположительно, вы уже знакомы с Storyboard, и знаете, что довольно просто встроить представление в интерфейс навигации. Все, что необходимо сделать, это всего лишь несколько кликов.
В SwiftUI обернуть List вью в NavigationView также очень просто. Все, что вам нужно сделать, это изменить код следующим образом:
...
var body : some View {
NavigationView {
List(tutors) { tutor in
...
}
}
}
...
Необходимо выполнить оборачивание кода List в NavigationView. По умолчанию панель навигации не имеет заголовка. Предварительный просмотр должен переместить список вниз, оставляя очень большой разрыв в середине. Это потому, что мы не установили заголовок для панели навигации. Чтобы исправить это, необходимо установить заголовок, добавив следующую строку кода (т.е. .navigationBarTitle ):
...
var body : some View {
NavigationView {
List(tutors) { tutor in
...
}
.navigationBarTitle(Text("Tutors"))
}
}
...
Теперь экран должен выглядеть примерно так:
Далее установим кнопку навигации. NavigationButton ведет на новый экран, который находится в стеке навигации. Подобно тому, как мы обернули List в NavigationView, необходимо обернуть содержимое List с помощью NavigationButton, как показано ниже:
...
var body : some View {
NavigationView {
List(tutors) { tutor in
NavigationButton(destination: Text(tutor.name)) {
Image(tutor.imageName)
VStack(alignment: .leading) {
Text(tutor.name)
Text(tutor.headline)
.font(.subheadline)
.color(.gray)
}
}
}
.navigationBarTitle(Text("Tutors"))
}
}
...
Теперь имя участника команды отображено в подробном представлении. Сейчас самое время проверить это.
В текущем режиме предварительного просмотра вы не можете взаимодействовать с представлением. Обычно, когда вы нажимаете на предварительный просмотр, происходит простое выделение кода. Чтобы выполнить тест и проверить взаимодействие с пользовательским интерфейсом, необходимо нажать кнопку воспроизведения в правом нижнем углу.
Вью станет темным, и возможно, придется подождать пару секунд, пока загрузится весь симулятор, прежде чем появится возможность реально взаимодействовать с представлениями.
Когда загрузка закончится, вы сможете нажать на ячейку, и она перейдет к новому представлению в стеке, в котором будет отображаться имя выбранной ячейки.
Прежде чем перейти к реализации детализированного представления, позвольте мне показать вам хитрый прием, который поможет сделать ваш код более разборчивым. ⌘+Click NavigationButton и выберите «Extract Subview».
Бум! Вы можете видеть, что весь код в NavigationButton был создан в совершенно новой структуре, которая делает его очень разборчивым. Переименуйте ExtractedView в TutorCell.
Теперь можно получить ошибку в TutorCell. Это потому, что у нас нет параметра tutor для передачи в эту структуру. Исправить ошибку очень просто. Добавьте новую константу в структуру TutorCell следующим образом:
struct TutorCell: View {
let tutor: Tutor
var body: some View {
...
}
}
А, в ContentView, добавьте отсутствующий параметр изменив строку на:
...
List(tutors) { tutor in
TutorCell(tutor: tutor)
}.navigationBarTitle(Text("Tutors"))
...
Вот и все! Имеется список и ячейки, все они хорошо продуманные и разложены в требуемом порядке! Далее мы собираемся создать детальный вид, который будет показывать всю информацию о преподавателе.
Создание представления для отображения детальной информаций.
Давайте создадим новый файл, перейдя в File > New > File. Под iOS выберите SwiftUI View и назовите этот файл TutorDetail.
В предварительном просмотре уже создался главный базовый вид. Давайте с ним поработаем. Сначала нажмите на кнопку « +» и поместите изображение над уже встроенным представлением Text. Установите имя изображения «Simon Ng». Должно появится изображение Саймона. Теперь измените код так, как показано ниже:
struct TutorDetail: View {
var body: some View {
//1
VStack {
//2
Image("Simon Ng")
.clipShape(Circle())
.overlay(
Circle().stroke(Color.orange, lineWidth: 4)
)
.shadow(radius: 10)
//3
Text("Simon Ng")
.font(.title)
}
}
}
В целом этот код достаточно понятен, но в случае если у Вам нужны разъяснения, не волнуйтесь. Вот, что происходит:
- Сначала мы упаковываем все наши представления в вертикальный стек. Это имеет решающее значение для макета дизайна, который мы будем принимать.
- Затем берем изображение Саймона и оживляем его. Сначала установим клипы изображения в форме круга. Вместо того, чтобы установить cornerRadius, это намного эффективнее, поскольку круг можно приспособить к различным размерам изображения. Мы добавляем наложение круга с белой рамкой, которая обеспечивает красивую оранжевую рамку. Наконец, мы добавим легкую тень, чтобы обеспечить некоторую глубину изображения.
- Наша последняя строка кода устанавливает шрифт имени преподавателя на шрифт заголовка.
Также необходимо добавить еще два текстовых вью: headline и bio. Перетащите два текстовых вью ниже текстового вью с именем преподавателя, и отредактируйте их:
struct TutorDetail: View {
var body: some View {
VStack {
Image("Simon Ng")
.clipShape(Circle())
.overlay(
Circle().stroke(Color.orange, lineWidth: 4)
)
.shadow(radius: 10)
Text("Simon Ng")
.font(.title)
Text("Founder of AppCoda")
Text("Founder of AppCoda. Author of multiple iOS programming books including Beginning iOS 12 Programming with Swift and Intermediate iOS 12 Programming with Swift. iOS Developer and Blogger.")
}
}
}
Хорошей новостью является то, что у нас есть текстовые вью. Плохая новость в том, что они плохо выглядят и не показывают разницу между заголовком и детальным описанием. Кроме того, текстовое вью биографии не отображает весь текст. Давайте исправим это.
Обновите код следующим образом:
struct TutorDetail: View {
var body: some View {
VStack {
Image("Simon Ng")
.clipShape(Circle())
.overlay(
Circle().stroke(Color.orange, lineWidth: 4)
)
.shadow(radius: 10)
Text("Simon Ng")
.font(.title)
//1
Text("Founder of AppCoda")
.font(.subheadline)
//2
Text("Founder of AppCoda. Author of multiple iOS programming books including Beginning iOS 12 Programming with Swift and Intermediate iOS 12 Programming with Swift. iOS Developer and Blogger.")
.font(.headline)
.multilineTextAlignment(.center)
}
}
}
- Сначала мы устанавливаем “Founder of AppCoda” со шрифтом subheadline.
- Точно так же мы устанавливаем текстовое представление биографии используя шрифт headline. Мы также выровняем текст с линией .multilineTextAlignment(.center)
Давайте исправим следующую ошибку. Нам необходимо отобразить весь текст текстового представления биографии. Это можно легко сделать, добавив новую строку кода:
...
Text("Founder of AppCoda. Author of multiple iOS programming books including Beginning iOS 12 Programming with Swift and Intermediate iOS 12 Programming with Swift. iOS Developer and Blogger.")
.font(.headline)
.multilineTextAlignment(.center)
.lineLimit(50)
...
Все выглядит хорошо. Есть одно последнее изменение дизайна, которое я хочу сделать. Заголовок и текстовые представления биографии находятся слишком близко друг к другу. Я хотел бы иметь некоторое пространство между этими двумя представлениями. Кроме того, я хотел бы добавить некоторые отступы ко всем вью, чтобы они не касались краев устройства. Убедитесь, что вы изменили код следующим образом:
struct TutorDetail: View {
var body: some View {
VStack {
Image("Simon Ng")
.clipShape(Circle())
.overlay(
Circle().stroke(Color.orange, lineWidth: 4)
)
.shadow(radius: 10)
Text("Simon Ng")
.font(.title)
Text("Founder of AppCoda")
.font(.subheadline)
//1
Divider()
Text("Founder of AppCoda. Author of multiple iOS programming books including Beginning iOS 12 Programming with Swift and Intermediate iOS 12 Programming with Swift. iOS Developer and Blogger.")
.font(.headline)
.multilineTextAlignment(.center)
.lineLimit(50)
//2
}.padding()
}
}
Здесь выполним несколько изменений:
- Добавить разделитель так же просто, как и вызвать Divider()
- Чтобы добавить отступы ко всему вертикальному стеку, необходимо вызвать .padding() в конце объявления VStack.
Это все! Поздравляю! Экран детального просмотра готов. Осталось только соединить наш список преподавателей и их детальное описание. Это довольно просто.
Передача данных
Для передачи данных необходимо объявить некоторые параметры в структуре TutorDetail. Перед объявлением переменной body добавьте следующие переменные:
var name: String
var headline: String
var bio: String
var body: some View {
...
}
Это параметры, которые мы передадим из ContentView. Проведите следующие изменения:
...
var body: some View {
VStack {
// 1
Image(name)
.clipShape(Circle())
.overlay(
Circle().stroke(Color.orange, lineWidth: 4)
)
.shadow(radius: 10)
//2
Text(name)
.font(.title)
//3
Text(headline)
.font(.subheadline)
Divider()
//4
Text(bio)
.font(.headline)
.multilineTextAlignment(.center)
.lineLimit(50)
//5
}.padding().navigationBarTitle(Text(name), displayMode: .inline)
}
...
- Заменим имя преподавателя для image на переменную name
- Заменим текст заголовка на переменную headline
- Наконец, заменим длинный абзац текста на переменную bio
- Также была добавлена строка кода, которая установит заголовок панели навигации на имя преподавателя.
И последнее, но не менее важное: нам необходимо добавить отсутствующие параметры в структуру TutorDetail_Previews.
#if DEBUG
struct TutorDetail_Previews : PreviewProvider {
static var previews: some View {
TutorDetail(name: "Simon Ng", headline: "Founder of AppCoda", bio: "Founder of AppCoda. Author of multiple iOS programming books including Beginning iOS 12 Programming with Swift and Intermediate iOS 12 Programming with Swift. iOS Developer and Blogger.")
}
}
#endif
В приведенном выше коде мы добавляем отсутствующие параметры и заполняем информацию той, что имели ранее.
Вы можете быть удивлены, что случилось с инструкциями #if DEBUG/#endif. Это означает, что любой код, заключенный в эти команды, будет выполнен только при предварительном просмотре для целей отладки. В вашем последнем приложении этого не будет.
Ничто не должно измениться, так как информация также неизменна.
И так, последний шаг — связать это представление со списком. Переключитесь на файл ContentView.swift. Все, что необходимо сделать, это изменить одну строку кода в структуре TutorCell. Измените код NavigationButton на ниже приведенный:
...
var body: some View {
return NavigationButton(destination: TutorDetail(name: tutor.name, headline: tutor.headline, bio: tutor.bio)) {
...
}
}
...
Вместо того, чтобы отобразить представление с именем преподавателя, необходимо изменить место назначения на TutorDetail при заполнении соответствующих данных. Данный код должен выглядеть следующим образом:
Нажмите кнопку воспроизведения и выполняйте взаимодействие с представлением. Если все работает хорошо, приложение будет также хорошо работать.
Просто выберите одну из записей участника:
И тогда будут отображены детали участника на детальном экране.
Заключение
В этой статье представлены основы SwiftUI. Теперь будет удобно создавать простые приложения, такие как планировщик задач и т.д. Я предлагаю взглянуть на некоторые из приведенных ниже ресурсов, таких как документация от компании Apple и сессии WWDC 2019, посвященные данному фреймворку.
SwiftUI Documentation
SwiftUI Tutorials
Introducing SwiftUI: Building Your First App
SwiftUI Essentials
Этот фреймворк — это будущее развития Apple, поэтому очень здорово, если вы начнете именно с него. Помните, что если вы не уверены в коде, попробуйте поработать с автоматическим предварительным просмотром и посмотрите, сможете ли вы внести изменения в пользовательский интерфейс напрямую, чтобы увидеть, как создается код. Если у вас есть какие-либо вопросы, не стесняйтесь, задавайте их в комментариях ниже.
Для справки вы можете скачать готовый проект здесь.
Учебник Swift — разработка приложения для iOS8 [Часть 1, Hello World!] / Habr
Предисловие
Недавно Apple представила общественности достаточно важное изменение в разработке iOS приложений, анонсировав новый язык программирования Swift. Я принял решение: изучая этот язык пошагово, я буду в своих статьях рассказывать обо всём, что мне удалось найти. Это лишь первый пост из многих на эту тему, но я надеюсь, что вы решите изучать язык вместе со мной!
Весьма вероятно, что многие примеры кода, представленные в постах, будут позже изменены. Это отчасти потому, что мой стиль программирования – написать сейчас, чтобы проверить идею, а потом заняться рефакторингом, а также отчасти это потому, что для меня (как и для многих других) Swift – абсолютно новый язык программирования. Так что, скорее всего, как только я узнаю что-нибудь новое, ход этих уроков будет меняться.
Итак, я собираюсь начать с довольно простого приложения. Также я буду объяснять, как работает код. Готовы? Поехали…
UPD: Статья написана в соответствии с изменениями в XСode 6 Beta 5
Основы
Swift отменяет использование стандарта объявления переменных, который использует имя типа перед объявлением переменной, вместо этого для объявления, как и в JavaScript, применяется ключевое слово
var
.Так, например, эта строка Objective-C
NSString *myString = @"This is my string.";
в Swift будет заменена на эту
var myString = "This is my string."
Для объявления констант используется ключевое слово
let
let kSomeConstant = 40
В данном случае
kSomeConstant
неявно определяется как целое число. Если же вы хотите конкретизировать тип, то вы можете это сделать так:let kSomeConstant: Int = 40
Немножко о Чистом КодеАвтор перевода рекомендует пользоваться вторым примером объявления констант. Довольно показательный пример описан в официальной документации:
let implicitInteger = 70
let implicitDouble = 70.0
let explicitDouble: Double = 70
В этом автор перевода солидарен с Helecta (см. соответствующий пост)
И массивы, и словари описываются с помощью
[]
var colorsArray = ["Blue", "Red", "Green", "Yellow"]
var colorsDictionary = ["PrimaryColor":"Green", "SecondaryColor":"Red"]
Это ещё далеко не всё, однако я считаю, что эти основы достаточно важны для дальнейшего чтения учебника. Итак, давайте перейдём к
Hello, World!
Hello, World!
В первую очередь, мы напишем самое простое приложение, которое только можно представить, чтобы начать работу —
Hello, World!
Наше приложение будет делать только одно: печатать фразу «Hello, World!» в консоль. Для этого нам потребуется установленная IDE XCode, для скачивания которой необходима учётная запись разработчика. Если у вас есть аккаунт, то смело качайте с официального сайта XCode 6 beta 4, желательно это сделать до прочтения ниже описанного.
Итак, вы установили свою копию IDE. Теперь давайте выведем «Hello, World!» на консоль.Этот пример не только демонстрирует простейшее приложение, которое можно написать, но и, что немаловажно, показывает, что среда разработки настроена правильно.
В XCode создайте проект с помощью шаблона приложения с одним видом («Single View Application»).
Убедитесь, что вы выбрали Swift в качестве языка приложения.
Теперь вы должны найти файл AppDelegate.swift в иерархии проекта. Внутри найдите следующую строку:
"// Override point for customization after application launch."
Замените эту строку на наш изумительный код:
println("Hello World")
Теперь нажмите «Run». Вы должны увидеть загрузившееся пустое приложение и слова
Hello, World!
, напечатанные в консоли, расположенной в нижней части окна XCode. Заметьте, это не будет отображаться в симуляторе iPhone. Поздравляю! Вы только что написали своё первое приложение на Swift! Правда оно не получит никаких премий, призов, только ваши собственные овации. А теперь, давайте копнём немножко глубже…
Добавление Table View
В этом разделе мы попробуем добавить материал на экран. Откройте в XCode файл Main.storyboard, перенесите из Библиотеки Объектов («Object Library») объект
Table View
на экран приложения, растяните таблицу так, чтобы она совпала с краями. Затем измените высоту, перетянув верхний край, оставив небольшое пространство сверху (это необходимо для строки состояния). Если вы запустите приложение, то увидите в симуляторе пустую таблицу.Теперь необходимо создать делегат и источник данных для таблицы. Это легче всего сделать в конструкторе интерфейса. Нажмите клавишу «Command», кликните и перетащите
Table View
к объекту View Controller
в иерархии файла .storyboard, и выберите «источник данных» («data source»). Повторите с опцией «delegate».Примечание:Я получил целую тонну вопросов о вышесказанном, т.к. многие люди сообщают о том, что у них не устанавливается табличный вид. Поэтому, я записал видео, поясняющее как работает подключение объектов Storyboard в коде. Для просмотра перейдите в полноэкранный режим и выберите опцию 720p, чтобы вы могли заметить всё, что вас интересует. Это будет немного отличаться от интерфейса XCode, но функционально всё работает также.
А теперь давайте углубимся в методы протоколов для табличного представления. Из-за использования UITableViewDataSource
и UITableViewDelegate
мы должны изменить определение класса.
Откройте файл и замените строку
class ViewController: UIViewController {
следующей
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
Если вы нажмёте клавишу «Command» и кликните на один из этих протоколов, то увидите «обязательные» функции. Для табличного представления необходимы как минимум эти две:
func tableView(tableView: UITableView!, numberOfRowsInSection section: Int) -> Int
func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell!
Изменим наш класс
View Controller
путём добавления этих двух функций:func tableView(tableView: UITableView!, numberOfRowsInSection section: Int) -> Int {
return 10
}
func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell! {
let cell: UITableViewCell = UITableViewCell(style: UITableViewCellStyle.Subtitle, reuseIdentifier: "MyTestCell")
cell.textLabel.text = "Row #\(indexPath.row)"
cell.detailTextLabel.text = "Subtitle #\(indexPath.row)"
return cell
}
Первый метод возвращает количество строк в разделе. В нашем примере используется «магическое» число 10, однако вместо него, как правило, должна использоваться длинна контроллера массива. Наш же код умышленно упрощён.
Во втором методе происходит чистой воды волшебство. Мы создаём экземпляр класса UITableViewCell
(cell
), используя стиль ячейки Subtitle
. Затем мы присваиваем текстовому значению этой ячейки значение "Row #\(indexPath.row)"
. В Swift подобным образом происходит встраивание значений переменных в строку без конвертации (таким образом, мы получим строки вида "Row #1"
, "Row #2"
)
Детализированная текстовая метка (detailTextLabel
) доступна только при использовании класса ячеек Subtitle
, который мы используем в данном примере.
При запуске приложения вы увидите восхитительный список ячеек с заголовками и подзаголовками, показывающие номера их строк. Это один из наиболее распространённых способов отображения данных в iOS, вы убедитесь, он вам ещё не раз пригодится. Увидеть полный текст кода вы можете на github.
В следующем посте мы исследуем использование API поиска iTunes для создания приложения, способного искать и отображать альбомы внутри iTunes Store.
Вопрос о дальнейшем переводе
Уважаемые Хабралюди! Если вы прочли этот перевод, помогите автору определиться с будущим цикла.
Для этого всего лишь требуется поучаствовать в опросе.
Swift Часть 2: Простое iOS приложение
Во втором туториале вы узнаете как создать свое первое приложение для iOS. Конкретно, что мы сделаем тут, так это создадим пользовательский интерфейс для нашего класса TipCalculator, который был в прошлом туториале. Мы написали наши уроки так, чтобы они были полезны как для совсем начинающих программистов iOS, так и для бывалых программистов, знакомящихся со Swift.
Для этого туториала вам понадобится Xcode минимальной версии 6.1.1 (время написания этой статьи). Вам не нужен какой-либо опыт в программировании на Swift или Objective-C, но если он все таки есть, то он лишь ускорит процесс усвоения материала.
Поехали!
Запустите Xcode и пройдите по File\New\Project. Выберите iOS\Application\Single View Application и нажмите Next.
В графе Product Name (имя приложения) напишите TipCalculator, установите Language на Swift и смените Devices на iPhone. Use Core Data выбирать не нужно. После, нажмите Next.
Выберите директорию для сохранения проекта и нажмите Create.
Давайте взглянем, что создал для нас Xcode: в верхнем левом углу выберите iPhone Simulator и нажмите кнопку Play.
Если вы все сделали правильно, то вы увидите симулятор с белым экраном:
Xcode создал одностраничное приложение с пустым белым экраном. Но не переживайте, в этом туториале вы его заполните!
Создаем модель приложения
Первое должно быть первым — до того как мы приступим к пользовательскому интерфейсу, вы должны создать модель приложения. Модель приложения — класс (или несколько классов), который отображает данные вашего класса и операции, которые будет проводить ваше приложение с этими данными.
В этом туториале ваша модель будет просто представлена классом TipCalculator, который вы создали на прошлом уроке, только мы переименуем его в TipCalculatorModel.
Давайте добавим класс в ваш проект. Чтобы это сделать нужно пройти File\New\File и выбрать iOS\Source\Swift File. Называем файл TipClculatorModel.swift и жмем Create.
Заметка
Вы не можете обратиться к коду, который располагается в файле Playground’а. Playground нужен только для тестирования вашего или его макетирования. Если вы хотите использовать код из playground’а, то вам придется просто его перенести в файл Swift, как мы и сделаем тут.
Откройте TipCalculator.swift и скопируйте туда ваш класс TipCalculator (но только класс и больше ничего!) из файла предыдущего туториала и сделайте следующее:
- Переименуйте класс в TipCalculatorModel
- Поменяйте total и taxPct из констант в переменные (потому что пользователь будет менять эти данные, когда запустит приложение)
- Из-за этого вам нужно поменять subtotal в вычисляемое свойство. Замените свойство subtotal на следующее:
var subtotal: Double {
get {
return total / (taxPct + 1)
}
}
Фактически, вычисляемое свойство не хранит значения. Вместо этого оно его вычисляет, каждый раз, основываясь на других значениях. Здесь subtotal считается каждый раз, когда мы обращаемся к нему, основываясь на значениях total и taxPct.
Заметка
Вы также можете использовать метод setter для вычисляемого свойства, если вам нравится синтаксис вроде этого:
var subtotal: Double {
get {
return total / (taxPct + 1)
}
set(newSubtotal) {
//...
}
}
Однако, setter будет обновлять ваши свойства total и taxPct, основываясь на newSubtotal, но для нас это бессмысленно, так что имплементировать это мы не будем.
- Удалите строку, которая устанавливает subtotal в init.
- Удалите все комментарии, которые есть в файле
В итоге у вас должно получиться следующее:
import Foundation
class TipCalculatorModel {
var total: Double
var taxPct: Double
var subtotal: Double {
get {
return total / (taxPct + 1)
}
}
init(total: Double, taxPct: Double) {
self.total = total
self.taxPct = taxPct
}
func calcTipWithTipPct(tipPct: Double) -> Double {
return subtotal * tipPct
}
func returnPossibleTips() -> [Int: Double] {
let possibleTipsInferred = [0.15, 0.18, 0.20]
let possibleTipsExplicit:[Double] = [0.15, 0.18, 0.20]
var retval = [Int: Double]()
for possibleTip in possibleTipsInferred {
let intPct = Int(possibleTip*100)
retval[intPct] = calcTipWithTipPct(possibleTip)
}
return retval
}
}
С моделью приложения мы разобрались, настало время поработать над интерфейсом!
Вступление в Storyboards и в Interface Builder
Заметка
Если вы уже бывалый разработчик под iOS, то эта статья и следующая будут для вас легкими. Для ускорения процесса вы можете сразу перейти в секцию «Обзор View Controller».
Вы создаете интерфейс приложения в Storyboard. В Xcode есть встроенный инструмент для удобного редактирования Storyboard, который называется Interface Builder.
В Interface Builder вы можете размещать: кнопки, текст, ярлыки и другие элементы (которые называются Views). Осуществляется все это с помощью простого перетягивания с панели, на экран вашего приложения.
Двигаемся дальше, нажмите на Main.storyboard в левой части Xcode, для того, чтобы показать Storyboard в Interface Builder.
Тут много всякого для изучения, так что давайте не будем сильно торопиться и будем двигаться постепенно:
- В левом краю у вас есть Project Navigator или навигатор проекта, где отображаются все файлы вашего проекта.
- Слева в Interface Builder располагается Document Outline (схема документа), где вы можете быстро взглянуть на все элементы располагающиеся на вашем «экране». При нажатии на стрелочки вы получите развернутую иерархию элементов вашего приложения на текущем «экране» (View Controller). На данный момент у вас всего один View Controller или «экран» с одним пустым белым View (смотри в иерархии). Мы скоро добавим сюда некоторые элементы.
- Стрелка слева от View Controller свидетельствует о том, что это входной View Controller или «экран», то есть это именно тот вид, который появляется при загрузке приложения. Вы можете изменить первоначальный «экран» просто перетащив стрелку на другой, которого у нас нет.
- Внизу Interface Builder’а вы видите что-то вроде «w Any», «h Any». Это значит, что вы редактируете ваш внешний вид приложения, который будет работать в интерфейсе любого размера. Вы можете сделать это через опцию Auto Layout. Кликнув на область экрана, вы можете переключить редактирование отображения для устройств принадлежащих определенному классу размеров. Об этом вы узнаете из наших будущих статей.
- Наверху View Controller’а вы увидите маленькие иконки, которые отображают сам View Controller, First Responder, Exit. Если вы немного программировали в Xcode ранее, то вы заметили, что эти иконки ранее были внизу. Этими иконками в этой статье мы пользоваться не будем, так что пока не берите в голову.
- Внизу справа Interface Builder’а четыре иконки для Auto Layout. Ну о них мы поговорим в следующих туториальных.
- Справа вверху Interface Builder’а располагается Inspectors (инспекторы) для выбранного вами элемента. Если у вас ничего нет, то пройдите по меню View\Utilities\Show Utilities. Обратите внимание, что тут несколько вкладок, мы будем использовать их в этом туториале для конфигурации вида.
- Внизу справа Interface Builder’а располагаются библиотеки или Libraries. Это перечень различных элементов, которые вы можете добавить к виду вашего приложения. Уже очень скоро мы перетащим несколько элементов из Libraryes на View Controller(экран) вашего приложения.
Создание элементов интерфейса приложения
Помните, что ваш класс TipCalculatorModel имеет два значения для ввода: общая сумма (total) и процент налога (tax percentage).
Было бы здорово, если бы пользователь смог вводить значения с цифровой клавиатуры, таким образом, текстовое поле (Text Field) подходит идеально для этих целей. Что же касается ввода процента налога, то обычно запрещено использовать его для маленьких значений, так что лучше мы будем использовать слайдер (Slider).
В дополнение к текстовому вводу и слайдеру, нам также нужно: установить ярлыки (Label), панель навигации для отображения названия приложения, кнопку для выполнения вычислений и еще одно текстовое поле для вывода результата.
Давайте детально рассмотрим пользовательский интерфейс.
- Navigation Panel (или панель навигации). Вместо того, чтобы добавить панель навигации напрямую, выберите ваш View Controller, выделив его в иерархии документов как на рисунке: После этого идите в Editor\Embed In\Navigation Controller. Это установит вам панель навигации в ваш View Controller (отныне экран будем называть именно так). Сделайте двойной щелчок на панели навигации (Navigation Bar, которая внутри вашего View Controller) и установите имя Tip Calculator.
- Labels (или ярлыки). Перетащите Label или по-русски «ярлык» в ваш View Controller. Сделайте двойной щелчок мыши по ярлыку Label и напишите Bill Total (Post-Tax):. Выберите Label и нажмите на пятую вкладку в Inspector, установите там X=33 и Y=81. Повторите все то же самое и для второго ярлыка, только назовите его Tax Percentage (0%): X=20 и Y=120.
- Text Field (текстовое поле). Из библиотеки элементов перетащите объект под названием Text Field в ваш View Controller. В инспекторе атрибутов (atribute inspector) установите Keyboard Type = Decimal Pad. В инспекторе размеров (Size Inspector) установите: X=192, Y=77 и Width=392. 
- Slider (или слайдер). Перетащите Slider из библиотеки в ваш View Controller. В Attribute Inspector установите Minimum Value=0 (минимальное значение), Maximum Value=10 (максимальное значение) и Current Value=6 (текущее значение). В Size Inspector установите X=190, Y=116 и Width=396.
- Button (или кнопка). Из Object Library (привыкаем к английскому) перетаскиваем Button (или кнопку) в ваш View Controller. Сделайте двойной щелчок на кнопке и переименуйте в Calculate. В Size Inspector установите X=268, Y=154.
- Text View. Из Object Library перетаскиваем Text View в ваш View Controller. Сделайте двойной щелчек на Text View и удалите текст плейсхолдера. В Attribute Inspector убедитесь в том, что Editable и Selectable не выбраны! В Size Inspector установите X=16, Y=192, Width=568, Height=400.
- Tap Gesture Recognizer (элемента, распознающий движения). Из Object Library перетаскиваем Tap Gesture Recognizer в ваш Main View (используйте иерархию элементов для того, чтобы точно выделить Main View, а не элемент внутри него). Эта штука будет работать тогда, когда пользователь будет нажимать на элемент view для того, чтобы клавиатура исчезла.
- Auto Layout или (автопозиционирование). Interface Builder часто делает всю грязную работу за нас, когда устанавливает ограничения расположения элементов самостоятельно. В нашем случае мы как раз это и можем использовать. Для того, чтобы это сделать, выберите Main View в иерархии документа и нажмите третью кнопку в правой нижней части Interface Builder’а. Выберете Add Missing Constraints (или добавить недостающие ограничения расположения элементов).
Теперь запустите свой симулятор iPhone 6 и вы должны увидеть, что базовый интерфейс пользователя уже работает!
Тур по View Controller
Заметка
Если вы сразу прыгнули до этой секции, то вот вам наш plaground в zip!
Только что вы создали модель и внешний вид приложения, теперь самое время разобраться с View Controller!
Откройте ViewController.swift. Тут находится код вашего одиночного View Controller’а (экрана) приложения. Эта штуковина отвечает за взаимодействие ваших элементов с вашей моделью.
Вы увидите, что этот класс уже имеет вот такой код внутри:
\\
import UIKit
// 2
class ViewController: UIViewController {
// 3
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
// 4
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Есть несколько моментов, c которыми в ы до сих пор не сталкивались. Давайте разберемся с ними по одному:
- iOS разделена на множество frameworks(или фреймворки), каждый из которых содержит различные наборы кода. До того как использовать эти наборы в вашем приложении, вы должны импортировать этот фреймворк. UIKit — фреймворк, который содержит базовые классы для работы с View Controller’ми и элементами управления, такими как: кнопки, поля ввода текста и множество других.
- Это первый пример, где вы видите класс, который является подклассом. Вы объявляете ViewController, который является подклассом UIViewController.
Заметка
Опытные разработчики заметили, что ненужно ставить префикс класса перед именем класса, как вы это делали в Objective-C для избежания совпадения имен (другими словами, вам не нужно называть это RWTViewController). Все потому, что в Swift есть пространство имен и классы, которые вы создали в вашем проекте.
Для того, чтобы вы поняли, что мы имеем в виду, замените объявление класса следующим кодом:
class UIViewController { } class ViewController: UIKit.UIViewController {
Здесь UIKit.UIViewController относится к классу UIViewController в пространстве имени UIKit. Так же как и TipCalculator.UIViewController будет относиться к к классу UIViewController в вашем проекте.
Не забудьте удалить этот тестовый код и вернуть предыдующее объявление ViewController
- Этот метод вызван корневым view этого View Controller’а, когда к нему получен доступ. Всякий раз, когда вы переписываете метод в Swift, вы должны использовать ключевое слово override. Это помогает избежать вам случайного изменения метода.
- Этот метод вызывается, когда у вашего устройства остается мало памяти. Это удачное место для чистки ваших ресурсов, которые вы можете припасти для дальнейших операций.
Соединяем ваш View Controller с вашими Views (элементами)
Сейчас, у вас уже сложилось правильное понимание класса View Controller, что ж, давайте добавим некоторые свойства для ваших subviews (элементов, которые находятся внутри view в иерархии документа) и подключим их в interface builder’е.
Для того, чтобы сделать это, добавьте следующие свойства в ваш класс ViewController(прямо перед viewDidLoad):
@IBOutlet var totalTextField : UITextField!
@IBOutlet var taxPctSlider : UISlider!
@IBOutlet var taxPctLabel : UILabel!
@IBOutlet var resultsTextView : UITextView!
Тут мы объявляем четыре переменные, прямо так, как вы изучили в нашем первом туториале: UITextField, UISlider, UILabel и UITextView.
Здесь всего два отличия:
- Вы пишите перед переменными ключевое слово @IBOutlet. Interface Builder сканирует код в поиске каких-либо свойств в вашем View Controller’е с этим словом. У найденных свойств он ищет соединения, так что вы смело можете их соединить с элементами (или Views).
- Вы обозначаете переменные восклицательным знаком (!). Это значит, что ваши переменные опциональны, но их значения неявно извлекаются. Этот замечательный способ сказать, что вы пишите код, предполагая, что они имеют значения, и ваше приложение завершится с ошибкой, если вдруг хотя бы одно из них окажется без значения, т.е. nil.Неявное извлекаемые опционалы — удобный способ для того, чтобы создать переменные, которым точно будут присвоены значения до того, как они будут использованы (как создание элементов пользовательского интерфейса в Storyboard), так что вы не должны извлекать значение опционала каждый раз перед использованием. Давайте попробуем соединить эти свойства с элементами пользовательского интерфейса.
Откройте Main.storyboard и выберите ваш View Controller (Tip Calculater в нашем случае) в иерархии документа (Document Outline). Откройте Connection Inspector (6 вкладка) и вы увидите все свойства, которые вы создали в секции Outlets.
Вы наверняка заметили маленький круг справа от resultsTextView. Удерживайте клавишу ctrl и перетащите курсор с него и до text view, который под Calculate button, и отпустите. Вы только что соединили свойство с элементом (или view).
Теперь, сами повторите тоже самое и для остальных трех свойств. Подключите каждое из них к соответствующему элементу пользовательского интерфейса.
Заметка
Есть даже более простой способ подключения свойств к элементам.
Пока вы держите Main.storyboard открытым, вы можете открыть Assiastand Editor (View\Assistant Editor\Show Assistant Editor), убедитесь, что ваш assistant editor отображает ваш код view controller’а.
После чего вы можете перетащить (с ctrl) ваш элемент в Assistant Editor, прямо до viewDidLoad. В появившемся окне вам будет нужно ввести имя свойства для того чтобы его создать, после чего жмем Connect.
Такой метод позволит вам создать свойство и сразу его подключить, и все это за один раз. Неплохо, правда?
Оба способа работают хорошо, а вот который вам ближе, решать вам.
Подсоединяем Actions(действия) к вашему View Controller’у
Точно также как вы соединили элементы со свойствами вашего view controller’а, вам нужно так же соединить определенные действия ваших элементов (например, нажатие кнопки) с методами вашего view controller’а.
Откроем ViewController.swift и добавим эти три метода в ваш класс:
@IBAction func calculateTapped(sender : AnyObject) {
}
@IBAction func taxPercentageChanged(sender : AnyObject) {
}
@IBAction func viewTapped(sender : AnyObject) {
}
Когда вы объявляете функции обратного вызова для действий с элементом они всегда должны иметь ту же подпись — функция без возвращаемого значения, которая принимает один параметр типа AnyObject, как параметр, который представляет класс любого типа.
Заметка
AnyObject — эквивалент для id в Objective-C.
Для того чтобы Interface Builder заметил ваши новые методы, вам нужно использовать ключевое слово @IBAction (точно так же как и в случае с @IBOutlet).
Далее, откройте Main.stroryboard и убедитесь что в схеме документа вы выделили свой view controller. Также убедитесь, что ваш Connections Inspector (6 вкладка) открыт и вы увидите новые методы в секции Recieved Actions.
Найдите кружок справа от calculateTapped и перетащите его на кнопку Calculate. В появившемся окне выберите Touch Up Inside:
Другими словами мы говорим :»Вызывать мой метод calculateTapped: тогда, когда пользователь уже убирает палец с экрана».
Теперь повторим то же самое для остальных двух методов:
- Перетащим taxPercentageChanged на ваш слайдер и соединим его с действием Value Changed, которое вызывается каждый раз, как только пользователь двигает слайдер.
- Перетащим viewTapped на Tap Gesture Recognizer в схему документа. Никаких действий для этого нет, так что ваш метод будет просто вызываться, когда распознает соответствующее движение.
Заметка
Точно так же как и в случае со свойствами, так и для методов, есть сокращенный вариант соединения с действиями, используя Interface Builder.
Вы можете просто ctrl-перетащить от, скажем, кнопки в ваш Swift код вашего View Controller’а в Assistant Editor. В появившемся окне вам нужно выбрать Action и дать имя вашего метода.
Таким образом вы создадите метод в вашем Swift файле и соедините его с действием всего за один шаг. И снова, используйте тот метод соединения, который вам больше всего нравится.
Соединение вашего View Controller’а с вашей моделью
Уже почти все закончили. Все что осталось сделать, так это соединить ваш View Controller с вашей моделью.
Откройте ViewController.swift и добавьте свойство для модели вашего класса и метод для обновления пользовательского интерфейса:
let tipCalc = TipCalculatorModel(total: 33.25, taxPct: 0.06)
func refreshUI() {
// 1
totalTextField.text = String(format: "%0.2f", tipCalc.total)
// 2
taxPctSlider.value = Float(tipCalc.taxPct) * 100.0
// 3
taxPctLabel.text = "Tax Percentage (\(Int(taxPctSlider.value))%)"
// 4
resultsTextView.text = ""
}
Давайте пройдемся в refreshUI по одной строчке:
- В Swift вам нужно явно конвертировать один тип в другой. Здесь мы конвертируем tipCalc.total из Double в String
- Вы хотите, чтобы процент налога отображался как целое число (то есть от 0%-10%), чем дробное (что-то вроде 0.06). Так что просто умножим на 100.
- Помните, что это действие необходимо, так как свойство taxPctSlider.value является типом Float.
- Тут мы используем интерполяцию для обновления ярылка, отображающего процент налога.
- Очищаем результат в текстовом поле (text view) до тех пор пока пользователь не нажал кнопку Calculate.
Следующее, добавим вызов refreshUI внизу в viewDidLoad:
refreshUI()
Так же имплементируем taxPercentageChanged и viewTapped:
@IBAction func taxPercentageChanged(sender : AnyObject) {
tipCalc.taxPct = Double(taxPctSlider.value) / 100.0
refreshUI()
}
@IBAction func viewTapped(sender : AnyObject) {
totalTextField.resignFirstResponder()
}
taxPercentageChanged просто обращает «умножение на 100», в то время как viewTapped вызывает resignFirstResponder в поле totalTextField, когда пользователь нажал на view(что и заставляет клавиатуру исчезнуть с экрана).
Остался один метод. Имплементируем calculateTapped:
@IBAction func calculateTapped(sender : AnyObject) {
// 1
tipCalc.total = Double((totalTextField.text as NSString).doubleValue)
// 2
let possibleTips = tipCalc.returnPossibleTips()
var results = ""
// 3
for (tipPct, tipValue) in possibleTips {
// 4
results += "\(tipPct)%: \(tipValue)\n"
}
// 5
resultsTextView.text = results
}
Давайте все разберем по порядку:
Заметка
Вот как это все работает, если вам это интересно.
Во время написания этого туториала класс String в Swift не имеет доступа ко всем методам, в отличии от NSString (NSString — класс в фреймворке Foundation). Если быть конкретным, то класс String в Swift не имеет метода, который бы преобразовывал тип String в тип Double, хотя NSSting такой метод имеет.
Вы можете вызвать (XXX as NSString)() в Swift для преобразования String в NSString. После чего вы можете использовать любой метод, доступный для NSString, например, метод, преобразующий String в Double.
- Тут нужно преобразовать тип String в Double. Это несколько коряво так делать, но думаем, уже скоро будет способ поприличнее.
- Здесь вы вызываете метод returnPossibleTips модели tipCalc, которая возвращает словарь с возможными процентами чаевых.
- Это то, как вы перебираете словарь через ключи и значения одновременно. Удобно, не так ли?
- Здесь мы используем интерполяцию строк, для создания строки, которую поместим в текстовое поле. Мы используем \n для начала новой строки.
- Наконец, мы присваиваем текстовому полю значение result.
Вот и все! Запускайте и наслаждайтесь вашим калькулятором чаевых!
Это конечный вариант нашего Xcode проекта.
Урок подготовил: Иван Акулов
Источник урока: http://www.raywenderlich.com/74904/swift-tutorial-part-2-simple-ios-app
Знакомьтесь, Swift! / Habr
2 июня на конференции WWDC 2014 Apple представила новый объектно-ориентированный язык программирования — Swift. Я думаю, многие уже успели посмотреть, что из себя представляет этот язык (Swift — нововведения), поэтому я не буду останавливаться на нововведениях. Я предлагаю создать простенький проект на языке Swift, чтобы понять на деле основные отличия от привычного Obj-C.Подготовка
Для начала необходимо установить Xcode 6 Beta. Скачать его можно отсюда:
https://developer.apple.com/devcenter/ios/index.action
Скачиваем, устанавливаем и открываем (проблем с установкой не должно возникнуть, beta версия ставится как отдельное приложение и на основной Xcode никак не влияет).
Создаем новый проект (Single View Application) -> вводим название проекта и не забываем выбрать язык Swift!
Структура
Обратите внимание на структуру, количество файлов теперь в 2 раза меньше, теперь нет необходимости в заголовочных файлах. Код, написанный в глобальной области используется в качестве точки входа для программы, так что больше не нужна функция main.
Вот как выглядит теперь AppDelegate:
import UIKit
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: NSDictionary?) -> Bool {
// Override point for customization after application launch.
return true
}
func applicationWillResignActive(application: UIApplication) {
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
}
func applicationDidEnterBackground(application: UIApplication) {
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}
func applicationWillEnterForeground(application: UIApplication) {
// Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
}
func applicationDidBecomeActive(application: UIApplication) {
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}
func applicationWillTerminate(application: UIApplication) {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}
}
Hello World
Изучение любого языка начинается с Hello World. Не станем нарушать традицию. Откройте AppDelegate.swift и добавьте в
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: NSDictionary?) -> Bool
строку:println("Hello World") //Выводит в консоль
Запустите программу и вы увидите в консоли заветный Hello World. Вот так все просто.
Усложним
Немного усложним проект. Добавим любимый TableView.
Открываем Main.storyboard. Кстати, обратите внимание что для универсального приложения теперь по умолчанию создается не два storyboard, как было раньше, а всего лишь один. Количество симуляторов тоже увеличилось:
Находим в Object Library заветный Table View и переносим его на экран приложения. Растягиваем таблицу, чтобы она была на весь экран (необходимо, чтобы она совпадала с краями).
Дальше все делается как и раньше, нам нужно задать для таблицы dataSource и delegate. Для этого открываем Connection Inspector, от delegate тянем к объекту ViewController и аналогично для dataSource.
Во ViewController.swift нужно указать протоколы, которые нам понадобятся: UITableViewDataSource и UITableViewDelegate
Теперь это можно сделать так:
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate
Компилятор сразу ругнется:
Type ‘ViewController’ does not conform to protocol ‘UITableViewDataSource’
Компилятор сообщает нам, что мы не определили функции протокола
'UITableViewDataSource'
. Чтобы посмотреть какие функции нужно определить, зажмите command + кликните по протоколу.protocol UITableViewDataSource : NSObjectProtocol {
func tableView(tableView: UITableView!, numberOfRowsInSection section: Int) -> Int
func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell!
Вот эти две функции и необходимо добавить в наш ViewController.swift
Первая функция должна возвращать количество строк в таблице (Int):
func tableView(tableView: UITableView!, numberOfRowsInSection section: Int) -> Int
{
return 20
}
А вторая функция возвращает ячейку таблицы:
func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell!
{
let cell: UITableViewCell = UITableViewCell(style: UITableViewCellStyle.Subtitle, reuseIdentifier: "MyTestSwiftCell")
cell.text = "Habrapost \(indexPath.row)"
cell.detailTextLabel.text = "Hi, \(indexPath.row)"
return cell
}
В первой строчке создаем ячейку. Разберем запись подробней:
let означает, что мы создаем константу, а не переменную.
let cell: UITableViewCell сообщаем, что тип этой константы будет UITableViewCell. По идее, необязательно сообщать какой тип будет у константы или переменной. Программа будет прекрасно работать и так:
let cell = UITableViewCell(style: UITableViewCellStyle.Subtitle, reuseIdentifier: "MyTestSwiftCell")
Но как мне кажется, лучше все-таки сообщать, Apple дает хороший пример почему:
let implicitInteger = 70
let implicitDouble = 70.0
let explicitDouble: Double = 70
Напомню, как мы создавали ячейку в Obj-C:
UITableCell *cell =[[UITableCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@"MyTestSwiftCell"]
Не нужен больше alloc, Swift все делает самостоятельно. Все методы, которые начинались с init были убраны, и теперь инициализация происходит в стиле Swift (т.е MyClass()). Причем инициализаторы с with тоже были преобразованы, то что шло после with — стало первым аргументом в инициализаторе Swift.
Вот эта запись мне особенно сильно понравилась:
cell.text = "Habrapost \(indexPath.row)"
В Obj-C, чтобы сделать простую операцию конкатенацию строк, нужно было изгаляться следующим образом:
cell.text = [NSString stringWithFormat:@"Habrapost %@", indexPath.row];
По мне, так это приятное изменение.
Скажем теперь мы захотели изменить цвет текста на стандартный фиолетовый. Сделать это можно аналогично тому как было в Obj-C, обратимся к методу класса
cell.detailTextLabel.textColor = UIColor.purpleColor()
В итоге, получаем
Немного о playground
Playground — это площадка, где можно поэкспериментировать, и если понравиться перенести в основной проект.
Для того, чтобы создать playgroung выберете File->New->File:
Вот и все, можно экспериментировать. Например, я добавила ячейку таблицы, чтобы увидеть как она будет выглядеть.
Подробней почитать можно здесь https://developer.apple.com/…
Заключение
На первый взгляд, мне язык понравился. Довольно легко будет перейти от Obj-C на Swift, к тому же Swift прекрасно уживается с Obj-C. Количество кода уменьшилось в разы, читаемость при этом увеличилась. С памятью теперь вообще возиться не надо, все это делает Swift.
Подробнее про Swift: The Swift Programming Language
12 книг для изучения языка программирования Swift
Темой этой статьи стал язык Swift. На нем написаны приложения для iOS и macOS. Язык достаточно молод и литературу на него не так просто найти, — пишет KV.BY. Причиной малого количества книг стало и то, что официальная электронная литература от разработчиков очень подробная и доступная для понимания. Часть книг из перечня только на английском языке. Русской литературы, к сожалению, очень немного. Поэтому, исходя из этого, статья будет поделена на русские и английские издания.
Swift. Основы разработки приложений под iOS и macOS
Отличная к
iOS программирование на Swift в примерах
Задача Итак, наша задача создать iOS приложение, в среде разработки Xcode, в котором будет всплывающее окно —Pop Up View, при этом все что сзади этого окна будет затемняться. Подобный прием использован во многих приложениях, но я не смог найти информацию …
Pop Up View пример Read More »
Пример использования библиотеки Alamofire Задача: создать iOS приложение в среде разработки Xcode 9 на языке программирования Swift 4, которое посылает HTTP запрос, а в ответ получает данные, которые обрабатывает и отображает в виде таблицы. После разработки у нас получится такое …
Alamofire на примере Read More »
Метки: alamofire, Swift 4Пример и памятка по основным командам LLDB для работы с breakpoint — точками останова.
Основные команды Terminal и начало работы в LLDB
Если в процессе разработки iOS приложения или любого другого приложения потребуется выяснить какое количество памяти используется в данный момент, то можно использовать следующую функцию: // // proSwift.ru // func report_memory() { var info = mach_task_basic_info() var count = mach_msg_type_number_t(MemoryLayout<mach_task_basic_info>.size)/4 let …
Вывод в консоль размера используемой памяти iOS Swift Read More »
Без долгих вступлений и СЕО-якорей — сразу к делу. Для того чтобы добавить разделитель триад к любым числовым значениям нужно написать два расширения — одно для класса Formatter, а второе для числового типа, например Int или UInt32.
Шаблон autoreleasepool используется в Swift при возврате объектов autorelease (созданных либо вашим кодом Objective-C, либо использованием классов Cocoa). autorelease в Swift функционирует так же, как в Objective-C. Для примера можно рассмотреть метод создания объектов NSImage / UIImage: // // proSwift.ru …
Память и autoreleasepool для циклов Read More »
Метки: Памятка для перечитыванияFlatMap против nil Если функция (метод или инициализатор) может вернуть nil, а мы будем использовать эту функцию в качестве преобразователя в .map, то можно сразу отсеять элементы nil и вернуть не опциональные элементы // // proSwift.ru // class Event { …
Полезности для перечитывания Read More »
Метки: Памятка для перечитыванияЗачем все это нужно? Обработка ошибок во время выполнения программы и самое главное — реакция приложения на эти ошибки — это хорошая практика для любого программного продукта. Согласитесь, если вы пользуетесь приложением и в какой-то момент оно без каких либо …
Обработка ошибок в Swift Read More »
Тернарный условный оператор Проверку на выполнение условий можно записать со помощью условного оператора if else // // proSwift.ru // // Swift 3 if batteryLow { replaceBattery() } else { plugAndPlay() } Тут все просто — если батарейки сели — нужно …
Тернарный условный оператор и оператор ?? Read More »
Онлайн-курсы программирования Swift для начинающих.
Программирование на Swift с нуля для начинающих.
Курс Swift для начинающих, разработанный специалистами нашей компании, ориентирован на людей, которые только начинают изучать основы программирования. Вот что говорят об этом курсе опытные разработчики мобильных приложений:- Swift для «чайников» — это то, что вполне доступно новичку. Вы учитесь создавать программы в рамках среды, заданной Apple. В определенной мере это ограничивает возможности, но вместе с тем помогает сконцентрироваться на главном, сохранить мотивацию.
- Обучение Swift с нуля в компании SwiftLab учитывает то, что этот язык постоянно развивается. Вы не просто изучаете основы мобильной разработки, но и одновременно совершенствуетесь.
Выбирая для себя программирование для iOS с нуля на Свифт, следует помнить, что этот язык был изначально разработан как более простая и эффективная альтернатива Objective-C. Это значит, что вам будет проще создавать свои приложения для Apple, а владельцы устройств получат больше удовольствия от использования программ за счет их интерактивности.
Наши обучающие курсы проходят в режиме онлайн, поэтому вы сами выбираете наиболее удобный график занятий и скорость освоения новых материалов.
Playground Swift для обучения работе с программным кодом.
Для изучения программирования iOS с нуля компанией Apple разработано специальное игровое приложение Swift Playgrounds. Это виртуальная игровая площадка для тех, кто хочет не только освоить язык программирования, но и увлекательно провести время.
Действия игры разворачивается в нескольких локациях. Чтобы управлять роботами и другими игровыми персонажами, необходимо использовать специальные команды на основе программного кода. Игра доставит немало удовольствия всем, кто изучает ios программирование с нуля, а также будет полезна более опытным разработчикам.
«Песочница» дает доступ к встроенным инструментам, позволяет работать над проектами и создавать собственные программы на основе шаблонов, поэтому игра будет интересна разработчикам с любым уровнем подготовки.