Лекция 14. Итоговая лекция. Экосистема и практика
1. Введение
Эта лекция завершает наш курс по Swift. Мы прошли путь от базового синтаксиса до протоколов, обобщений и обработки ошибок. Теперь пора посмотреть на Swift как на полноценную экосистему: система управления пакетами, стандартная библиотека, серверная разработка и лучшие практики. Всё, что рассмотрено ниже, работает на Linux без Xcode.
2. Swift Package Manager (SPM) — полное руководство
SPM — встроенный инструмент для управления зависимостями и сборки проектов. Входит в поставку Swift — отдельная установка не нужна.
2.1 Создание пакета и структура проекта
mkdir MyApp && cd MyAppswift package init --type executableПараметр --type executable создаёт исполняемый проект (--type library — для библиотеки). Создаётся структура: Package.swift (манифест), Sources/ (код), Tests/ (тесты).
2.2 Файл Package.swift: targets, dependencies
Манифест написан на самом Swift:
import PackageDescription
let package = Package( name: "MyApp", targets: [ .executableTarget(name: "MyApp"), .testTarget(name: "MyAppTests", dependencies: ["MyApp"]), ])2.3 Добавление зависимостей из GitHub
import PackageDescription
let package = Package( name: "MyApp", dependencies: [ .package(url: "https://github.com/apple/swift-argument-parser", from: "1.3.0"), ], targets: [ .executableTarget( name: "MyApp", dependencies: [ .product(name: "ArgumentParser", package: "swift-argument-parser"), ] ), ])Использование подключённой библиотеки:
import ArgumentParser
@mainstruct Greet: ParsableCommand { @Argument(help: "Имя для приветствия") var name: String
func run() { print("Привет, \(name)!") }}2.4 Сборка и запуск
swift build # Компиляция проектаswift run # Сборка и запускswift test # Запуск тестовswift build -c release # Сборка в режиме релизаswift package clean # Очистка артефактов (.build/)2.5 Сравнение с pip/pyproject.toml
| Аспект | Swift (SPM) | Python (pip) |
|---|---|---|
| Манифест | Package.swift (Swift) | pyproject.toml / requirements.txt |
| Установка зависимостей | swift build (автоматически) | pip install -r requirements.txt |
| Запуск тестов | swift test | pytest |
| Изоляция | На уровне пакета (.build/) | venv / virtualenv |
3. Обзор стандартной библиотеки Swift
Стандартная библиотека доступна без импорта — загружается автоматически.
3.1 Строки, коллекции, числовые типы
let emoji = "Привет 🌍"print(emoji.count) // 9 (символов, не байтов)print(emoji.utf8.count) // 16 (байтов в UTF-8)
let numbers: [Int] = [3, 1, 4, 1, 5]let sorted = numbers.sorted()let unique = Set(numbers)
let capitals = ["Россия": "Москва", "Франция": "Париж"]let maxInt = Int.max // 64-бит на Linux3.2 Sequence и Collection протоколы
Эти протоколы дают единообразный доступ к элементам коллекций:
let words = ["Swift", "на", "Linux"]
// Из Sequencelet upper = words.map { $0.uppercased() } // ["SWIFT", "НА", "LINUX"]let long = words.filter { $0.count > 2 } // ["Swift", "Linux"]let joined = words.joined(separator: " ") // "Swift на Linux"
// Из Collectionprint(words.first ?? "пусто") // Swiftprint(words.isEmpty) // falseВ Python аналоги: __iter__ — для Sequence, Sized + Iterable + Container — для Collection.
4. Foundation на Linux
4.1 Что доступно
Начиная со Swift 5.9+ на Linux доступна переписанная на Swift версия Foundation:
import Foundation
// Дата и времяlet now = Date()let formatter = ISO8601DateFormatter()print(formatter.string(from: now))
// JSONstruct User: Codable { let name: String; let age: Int }let user = User(name: "Анна", age: 22)let data = try JSONEncoder().encode(user)let decoded = try JSONDecoder().decode(User.self, from: data)
// Файловая системаlet fm = FileManager.defaultprint(fm.currentDirectoryPath)
// URLlet url = URL(string: "https://example.com/api")!print(url.host ?? "") // example.com4.2 Что работает иначе или отсутствует
На Linux недоступны компоненты Apple-платформ: UIKit, AppKit — полностью отсутствуют; URLSession — работает, но может отличаться поведением; NSAttributedString — ограниченная поддержка.
4.3 import Foundation vs import FoundationEssentials
import Foundation // Полный набор: сеть, дата, JSON, файлыimport FoundationEssentials // Только базовое: Date, Data, UUID, JSONFoundationEssentials быстрее компилируется и не тянет сетевые компоненты.
5. Серверный Swift
5.1 Обзор Vapor — маршруты, обработчики, middleware
Vapor — самый популярный серверный фреймворк. Предоставляет маршрутизацию, middleware, ORM (Fluent), шаблонизатор (Leaf).
Package.swift для Vapor-проекта:
import PackageDescription
let package = Package( name: "MyServer", dependencies: [ .package(url: "https://github.com/vapor/vapor.git", from: "4.90.0"), ], targets: [ .executableTarget( name: "MyServer", dependencies: [.product(name: "Vapor", package: "vapor")] ), ])5.2 Пример HTTP-сервера на Vapor
import Vapor
let app = try Application(.detect())defer { app.shutdown() }
app.get { req in "Добро пожаловать на сервер Swift!" }
app.get("hello", ":name") { req -> String in let name = req.parameters.get("name")! return "Привет, \(name)!"}
struct Message: Content { let text: String }
app.post("json") { req -> String in let message = try req.content.decode(Message.self) return "Получено: \(message.text)"}
try app.run()swift run# curl http://localhost:8080/hello/Swift → Привет, Swift!5.3 Swift NIO
Swift NIO — низкоуровневый событийно-ориентированный фреймворк (аналог asyncio в Python). Vapor построен поверх NIO. Напрямую NIO используют для кастомных протоколов и высоконагруженных сервисов.
| Аспект | Swift (Vapor / NIO) | Python (Flask / asyncio) |
|---|---|---|
| Производительность | Компилируемый, быстрый | Интерпретируемый, медленнее |
| Типобезопасность | На этапе компиляции | Опциональная (type hints) |
| Конкурентность | Async/await + NIO | Async/await + asyncio |
6. Кроссплатформенные применения
6.1 CLI-утилиты
import ArgumentParser
@mainstruct WordCount: ParsableCommand { static let configuration = CommandConfiguration(abstract: "Подсчёт слов")
@Argument(help: "Текст для подсчёта") var text: String
func run() { print("Количество слов: \(text.split(separator: " ").count)") }}6.2 Утилиты обработки данных
import Foundation
let csv = """имя,возраст,городАнна,22,МоскваБорис,25,Казань"""
struct Person: Codable { let name: String; let age: Int; let city: String }
let people = csv.split(separator: "\n").dropFirst().map { line -> Person in let f = line.split(separator: ",") return Person(name: String(f[0]), age: Int(f[1])!, city: String(f[2]))}
let encoder = JSONEncoder()encoder.outputFormatting = [.prettyPrinted, .sortedKeys]print(String(data: try encoder.encode(people), encoding: .utf8)!)6.3 Скрипты автоматизации
Swift можно запускать как скрипт — без создания пакета:
#!/usr/bin/env swiftimport Foundation
let fm = FileManager.defaultlet contents = try fm.contentsOfDirectory(atPath: "/tmp")let weekAgo = Date().addingTimeInterval(-7 * 24 * 3600)
for item in contents { let attrs = try fm.attributesOfItem(atPath: "/tmp/\(item)") if let mod = attrs[.modificationDate] as? Date, mod < weekAgo { try? fm.removeItem(atPath: "/tmp/\(item)") }}Запуск: chmod +x script.swift && ./script.swift.
7. Код-стайл и лучшие практики
7.1 Swift API Design Guidelines
Официальное руководство: swift.org/documentation/api-design-guidelines. Принципы: ясность важнее краткости, имена должны быть самодокументирующими, sorted() возвращает новое — sort() изменяет на месте.
7.2 Именование: camelCase, UpperCamelCase
// Типы, протоколы — UpperCamelCasestruct StudentRecord { }protocol DataProvider { }
// Переменные, функции — lowerCamelCaselet studentName = "Иван"func calculateAverage(of scores: [Double]) -> Double { scores.reduce(0, +) / Double(scores.count) }
// Логические свойства — как утвержденияvar isEmpty: Bool { items.count == 0 }В Python: snake_case для функций и переменных, PascalCase только для классов.
7.3 Предпочтение struct над class
Используйте struct по умолчанию. class — только когда нужно наследование или ссылочная семантика:
struct Point { var x: Double; var y: Double } // значимый тип ✓class DatabaseConnection { var isConnected = false } // ссылочный тип — для общих ресурсов7.4 Использование guard для раннего выхода
// Плохо — глубокая вложенностьfunc process(_ data: [String: String]) { if let name = data["name"] { if let ageStr = data["age"], let age = Int(ageStr) { print("\(name), \(age)") } }}
// Хорошо — guard + ранний выходfunc process(_ data: [String: String]) { guard let name = data["name"] else { return } guard let ageStr = data["age"], let age = Int(ageStr) else { return } print("\(name), \(age)")}7.5 Избегание force unwrapping
let input: String? = nil
// let value = input! // Крах программы!let safe1 = input ?? "по умолчанию" // nil coalescinglet safe2 = input?.count // optional chaining → nil8. Подведение итогов курса
За 14 лекций мы рассмотрели:
| Лекция | Тема |
|---|---|
| 1 | Введение в Swift, установка на Linux, первая программа |
| 2 | Переменные, типы данных, операторы |
| 3 | Управляющие конструкции: if, switch, циклы |
| 4 | Функции и замыкания |
| 5 | Строки и коллекции |
| 6 | Структуры и классы |
| 7 | Перечисления и опционалы |
| 8 | Свойства и методы |
| 9 | Протоколы и расширения |
| 10 | Протокольно-ориентированное программирование |
| 11 | Обобщения (Generics) |
| 12 | Обработка ошибок и управление памятью |
| 13 | Конкурентность: async/await, Task, акторы |
| 14 | Экосистема, SPM, серверный Swift, практики |
Вы освоили: систему типов, протоколы, обобщения, обработку ошибок, ARC, конкурентность и инструменты разработки — всё на Linux.
9. Рекомендации для дальнейшего изучения
Официальные ресурсы:
- swift.org/documentation — The Swift Programming Language (бесплатная книга)
- swift.org/documentation/api-design-guidelines — руководство по API
- github.com/swiftlang/swift-evolution — предложения по развитию языка
Серверная разработка: docs.vapor.codes (Vapor), swift.org/server (общее), Hummingbird — лёгковесная альтернатива Vapor.
Проекты для практики:
- CLI-утилита — менеджер задач с хранением в JSON-файле
- REST API на Vapor с CRUD-операциями и SQLite
- Парсер CSV/JSON с выводом статистики
- Собственный Swift-пакет, опубликованный на GitHub
Книги: Swift in Depth (Tjeerd in ‘t Veen), Server-Side Swift with Vapor, Advanced Swift (objc.io).
10. Упражнения
Упражнение 1. Создайте Swift-пакет Greeting с функцией greet(name: String) -> String. Напишите тест, проверяющий результат. Запустите swift build и swift test.
Упражнение 2. Напишите CLI-утилиту, принимающую путь к JSON-файлу и выводящую его в отформатированном виде. Используйте Foundation и JSONSerialization.
Упражнение 3. Создайте Codable-структуру Config с полями host, port, debug. Реализуйте чтение из JSON-файла, обработайте ошибки через do-catch без force unwrapping.
Упражнение 4. Перепишите любой Python-скрипт на Swift. Сравните читаемость и типобезопасность.
Упражнение 5. Создайте Vapor-сервер с маршрутами GET /, GET /time, POST /echo. Протестируйте через curl.
11. Вопросы для самопроверки
- Какой командой создаётся новый исполняемый Swift-пакет?
- В каком файле описываются зависимости проекта? На каком языке он написан?
- Чем
swift buildотличается отswift run? - Какие протоколы стандартной библиотеки обеспечивают итерирование и индексный доступ?
- Что даёт
import FoundationEssentialsпо сравнению сimport Foundation? - Назовите два фреймворка для серверной разработки на Swift.
- Почему рекомендуется использовать
structпо умолчанию? - Чем
guard letлучше вложенныхif let? - Почему следует избегать force unwrapping (
!)? - Какие соглашения об именовании приняты для типов и переменных в Swift?