Добавить объявление

Пять инструментов отладки в Swift, которые часто используют сеньоры

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

assert - ловим логические ошибки на этапе разработки:


assert проверяет условие и, если оно ложно, останавливает выполнение программы. Работает только в дебаг-сборке - в релизе эти проверки просто вырезаются.

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

func calculateSquare(x: Double) -> Double {
assert(x != 0, "Число не может быть нулем")
return x * x
}

Если кто-то случайно вызовет calculateSquare(x: 0), приложение упадет с сообщением об ошибке. И вы сразу увидите проблему, а не будете полдня выяснять, почему результат не сошелся.

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

#file, #function, #line - добавляем контекст в логи:


Обычный print выводит просто сообщение. Чтобы понять, откуда оно пришло, приходится лезть в код. Есть способ лучше - использовать литералы #file#function и #line. Они подставляют имя файла, функции и номер строки прямо во время компиляции.

Оборачиваем print в удобную функцию:

func log(_ message: String,
file: String = #file,
function: String = #function,
line: Int = #line) {
print("[\(file):\(line)] \(function) - \(message)")
}

Теперь вместо print("Ошибка") пишем log("Ошибка"), и получаем в консоли что-то вроде:

[ViewController.swift:42] updateUser() - Ошибка

Никакого копирования имен функций и номеров строк руками. Все само подставляется.

CustomDebugStringConvertible - настраиваем вывод своих типов:


Когда вы пишете print(user), Swift выводит стандартное представление: User(name: "Artem", age: 33, role: "Admin"). Для маленьких структур ок, но когда полей много - в консоли каша.

Протокол CustomDebugStringConvertible позволяет переопределить этот вывод:

extension User: CustomDebugStringConvertible {
var debugDescription: String {
"👤 \(name), роль: \(role)"
}
}

Теперь print(user) покажет: "👤 Artem, роль: Admin". Коротко и понятно. Часто используемые типы данных можно снабдить такими расширениями - и отладка станет намного приятнее.

Mirror - смотрим на свойства объекта без документации:


Иногда нужно быстро посмотреть, какие поля у объекта и какие у них значения. Например, вы работаете с чужим кодом или отлаживаете сложную модель.

Mirror - это инструмент рефлексии, который позволяет заглянуть внутрь любого экземпляра:

func showProperties(_ value: T) {
let mirror = Mirror(reflecting: value)
for child in mirror.children {
print("\(child.label ?? "unknown"): \(child.value)")
}
}

Передаете любую структуру или класс:

let user = User(name: "Artem", age: 33, role: "Admin")
showProperties(user)

В консоли:

name: Artem
age: 33
role: Admin

Mirror работает даже со SwiftUI вьюхами - можно посмотреть, какие @State у них внутри. Полезная штука, когда нет документации или лень подключать дебаггер.

dump - печатаем сложные структуры с отступами:


Если у вас вложенный объект внутри другого объекта, обычный print выдаст что-то нечитаемое. Функция dump() решает эту проблему. Она рекурсивно печатает все содержимое, сохраняя иерархию.

Пример:

struct User {
let name: String
let age: Int
let address: Address
}

struct Address {
let city: String
let street: String
}

let user = User(name: "Artem", age: 33, address: Address(city: "Moscow", street: "Tverskaya"))
dump(user)

В консоли увидите:

User
- name: "Artem"
- age: 33
address: Address
- city: "Moscow"
- street: "Tverskaya"

dump показывается тип каждого значения и его вложенность. Особенно удобно для отладки массивов, словарей и Core Data объектов.

Вывод:


Сеньоры используют эти пять инструментов не потому, что они умнее, а потому что так быстрее. assert, литералы #file#function и #line, протокол CustomDebugStringConvertible, тип Mirror и функция dump встроены в стандартную библиотеку Swift и доступны без подключения дополнительных зависимостей. Перестаньте терять часы на однообразный print и просто начните применять то, что уже есть под рукой. Отладка станет чище, а логи - понятнее.
10.06.2026 27 556