Перейти к содержимому

Лекция 14. Итоговая лекция. Экосистема и практика

1. Введение

Эта лекция завершает наш курс по Swift. Мы прошли путь от базового синтаксиса до протоколов, обобщений и обработки ошибок. Теперь пора посмотреть на Swift как на полноценную экосистему: система управления пакетами, стандартная библиотека, серверная разработка и лучшие практики. Всё, что рассмотрено ниже, работает на Linux без Xcode.


2. Swift Package Manager (SPM) — полное руководство

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

2.1 Создание пакета и структура проекта

Окно терминала
mkdir MyApp && cd MyApp
swift package init --type executable

Параметр --type executable создаёт исполняемый проект (--type library — для библиотеки). Создаётся структура: Package.swift (манифест), Sources/ (код), Tests/ (тесты).

2.2 Файл Package.swift: targets, dependencies

Манифест написан на самом Swift:

5.10
import PackageDescription
let package = Package(
name: "MyApp",
targets: [
.executableTarget(name: "MyApp"),
.testTarget(name: "MyAppTests", dependencies: ["MyApp"]),
]
)

2.3 Добавление зависимостей из GitHub

5.10
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
@main
struct 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 testpytest
ИзоляцияНа уровне пакета (.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-бит на Linux

3.2 Sequence и Collection протоколы

Эти протоколы дают единообразный доступ к элементам коллекций:

let words = ["Swift", "на", "Linux"]
// Из Sequence
let upper = words.map { $0.uppercased() } // ["SWIFT", "НА", "LINUX"]
let long = words.filter { $0.count > 2 } // ["Swift", "Linux"]
let joined = words.joined(separator: " ") // "Swift на Linux"
// Из Collection
print(words.first ?? "пусто") // Swift
print(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))
// JSON
struct 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.default
print(fm.currentDirectoryPath)
// URL
let url = URL(string: "https://example.com/api")!
print(url.host ?? "") // example.com

4.2 Что работает иначе или отсутствует

На Linux недоступны компоненты Apple-платформ: UIKit, AppKit — полностью отсутствуют; URLSession — работает, но может отличаться поведением; NSAttributedString — ограниченная поддержка.

4.3 import Foundation vs import FoundationEssentials

import Foundation // Полный набор: сеть, дата, JSON, файлы
import FoundationEssentials // Только базовое: Date, Data, UUID, JSON

FoundationEssentials быстрее компилируется и не тянет сетевые компоненты.


5. Серверный Swift

5.1 Обзор Vapor — маршруты, обработчики, middleware

Vapor — самый популярный серверный фреймворк. Предоставляет маршрутизацию, middleware, ORM (Fluent), шаблонизатор (Leaf).

Package.swift для Vapor-проекта:

5.10
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 + NIOAsync/await + asyncio

6. Кроссплатформенные применения

6.1 CLI-утилиты

import ArgumentParser
@main
struct 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 swift
import Foundation
let fm = FileManager.default
let 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

// Типы, протоколы — UpperCamelCase
struct StudentRecord { }
protocol DataProvider { }
// Переменные, функции — lowerCamelCase
let 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 coalescing
let safe2 = input?.count // optional chaining → nil

8. Подведение итогов курса

За 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. Рекомендации для дальнейшего изучения

Официальные ресурсы:

Серверная разработка: docs.vapor.codes (Vapor), swift.org/server (общее), Hummingbird — лёгковесная альтернатива Vapor.

Проекты для практики:

  1. CLI-утилита — менеджер задач с хранением в JSON-файле
  2. REST API на Vapor с CRUD-операциями и SQLite
  3. Парсер CSV/JSON с выводом статистики
  4. Собственный 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. Вопросы для самопроверки

  1. Какой командой создаётся новый исполняемый Swift-пакет?
  2. В каком файле описываются зависимости проекта? На каком языке он написан?
  3. Чем swift build отличается от swift run?
  4. Какие протоколы стандартной библиотеки обеспечивают итерирование и индексный доступ?
  5. Что даёт import FoundationEssentials по сравнению с import Foundation?
  6. Назовите два фреймворка для серверной разработки на Swift.
  7. Почему рекомендуется использовать struct по умолчанию?
  8. Чем guard let лучше вложенных if let?
  9. Почему следует избегать force unwrapping (!)?
  10. Какие соглашения об именовании приняты для типов и переменных в Swift?