- Объявлять протокол, создавать соответствующие ему типы и добавлять методы с помощью расширений
- Выбрасывать и перехватывать ошибки с помощью
throws,throw,tryиdo-catch - Читать простое представление SwiftUI и объяснять роль
@State
Представь электрическую розетку: зарядка телефона, чайник, лампа — совсем разные устройства, но их вилки сделаны по одному правилу, поэтому подходят к любой розетке. В Swift такое правило называется протоколом. В этом уроке ты изучишь протоколы и обработку ошибок, а в конце познакомишься с экраном на SwiftUI, который объединяет всё, что ты уже знаешь.
Протоколы и расширения
Набор правил, описывающий, какие свойства и методы должны быть у типа. В самом протоколе кода нет; каждый тип, который ему соответствует (по-английски conform), сам выполняет эти требования.
Ниже протокол Shape требует, чтобы у каждой фигуры были имя и площадь. Rectangle и Square — совершенно разные структуры, но обе соответствуют протоколу, поэтому их можно хранить в одном массиве. А расширение (extension) протокола даёт всем соответствующим типам готовый метод summary().
protocol Shape {
var name: String { get }
func area() -> Double
}
extension Shape {
func summary() -> String {
"\(name): area \(area())"
}
}
struct Rectangle: Shape {
let width, height: Double
var name: String { "Rectangle" }
func area() -> Double { width * height }
}
struct Square: Shape {
let side: Double
var name: String { "Square" }
func area() -> Double { side * side }
}
let shapes: [any Shape] = [Rectangle(width: 4, height: 2.5), Square(side: 3)]
for shape in shapes {
print(shape.summary())
}Rectangle: area 10.0 Square: area 9.0
С помощью расширения можно добавлять новые свойства и методы к существующим типам — даже к встроенным Int и String. Внутри расширения self — это само значение.
extension Int {
var isEven: Bool {
self % 2 == 0
}
func times(_ action: () -> Void) {
for _ in 0..<self {
action()
}
}
}
print(7.isEven)
print(10.isEven)
3.times {
print("Swift!")
}false true Swift! Swift! Swift!
Обработка ошибок
Некоторые операции могут не удаться: на счёте не хватает денег, файл не найден, пропал интернет. В Swift такая функция помечается словом throws, а когда что-то идёт не так, она выбрасывает ошибку через throw. Ошибка обычно — перечисление, соответствующее протоколу Error. При вызове такой функции перед ней пишут try, а ошибку перехватывают в блоке do-catch.
enum WithdrawError: Error {
case invalidAmount
case insufficientFunds(needed: Int)
}
func withdraw(_ amount: Int, from balance: Int) throws -> Int {
guard amount > 0 else {
throw WithdrawError.invalidAmount
}
guard amount <= balance else {
throw WithdrawError.insufficientFunds(needed: amount - balance)
}
return balance - amount
}
do {
let left = try withdraw(30, from: 100)
print("Left: \(left) AZN")
_ = try withdraw(200, from: left)
print("This line is skipped")
} catch WithdrawError.insufficientFunds(let needed) {
print("Not enough money, need \(needed) AZN more")
} catch {
print("Other error: \(error)")
}Left: 70 AZN Not enough money, need 130 AZN more
Проследи, как выполняется программа: первый вызов успешен, и остаётся 70 манатов. Второй вызов выбрасывает ошибку, поэтому остаток блока do пропускается и управление переходит в подходящий catch. Последний catch ловит все остальные ошибки, и внутри него ошибка автоматически называется error.
Первый экран на SwiftUI
SwiftUI — инструмент Apple для создания интерфейсов. В нём ты не рисуешь экран шаг за шагом, а просто описываешь, как он должен выглядеть — это называется декларативным подходом. Код ниже — экран, счётчик которого растёт при каждом нажатии на кнопку. Запустить его можно только в Xcode или Swift Playgrounds, но каждую строку ты уже можешь понять.
import SwiftUI
struct ContentView: View {
@State private var count = 0
var body: some View {
VStack(spacing: 16) {
Text("Taps: \(count)")
.font(.largeTitle)
Button("Tap me") {
count += 1
}
.buttonStyle(.borderedProminent)
}
.padding()
}
}
#Preview {
ContentView()
}struct ContentView: View— экран — обычная структура, соответствующая протоколуView. Протокол требует лишь одного: свойстваbody.var body: some View— вычисляемое свойство, которое возвращает то, что показывается на экране.VStackрасполагает элементы вертикально,Textпоказывает текст, а замыкание в концеButtonвыполняется при нажатии.- Модификаторы вроде
.font(...)и.padding()меняют внешний вид и записываются цепочкой через точку. #Previewпоказывает живой предпросмотр экрана на холсте (canvas) Xcode.
Изменяемое значение, которое хранит представление. Когда значение @State меняется, SwiftUI автоматически пересчитывает body и обновляет экран — менять Text вручную не нужно.
- 1Создай проект
В Xcode выбери
File › New › Project…, возьми шаблонAppв разделеiOSи убедись, что в качестве интерфейса выбранSwiftUI. - 2Напиши код
Открой файл
ContentView.swiftи введи туда код выше. - 3Посмотри предпросмотр
Экран сразу появится на холсте справа; нажми кнопку и проверь, что счётчик растёт.
- 4Запусти в симуляторе
Выбери модель iPhone вверху и нажми
Cmd+R— приложение откроется в симуляторе iPhone.
Главное
- Протокол описывает, что должно быть у типа; соответствующие типы сами выполняют требования.
extensionдобавляет новые методы к существующим типам — даже кInt— и к протоколам.- Функция с
throwsвыбрасывает ошибки черезthrow; её вызывают сtryи перехватывают ошибки вdo-catch. try?превращает ошибку вnil, аtry!при ошибке роняет программу.- SwiftUI описывает экран как структуру, соответствующую
View; при изменении@Stateэкран обновляется автоматически.
Проверь себя
Вопросов: 10. Каждый правильный ответ приносит XP.