Программирование
10 ловушек Swift, которые вы не заметите, пока не станет слишком поздно
То, что код компилируется, не означает, что он безопасен.
Вы не узнаете об этом из курса или блогов. Эти знания получены из реальных ошибок в продакшене, работы по ночам и того одного сбоя, который мы не могли воспроизвести в течение нескольких недель.
Вот 10 ловушек Swift, которые кажутся безобидными — пока не настигнут вас.
1. Сильные циклы ссылок в замыканиях
Замыкания по умолчанию захватывают self. Если вы не используете [weak self], вы можете получить цикл удержания и утечку памяти.
class ProfileViewModel {
var onUpdate: (() -> Void)?
func setup() {
onUpdate = {
self.doSomething() // ⚠️ This captures self strongly
}
}
}
Исправление:
onUpdate = { [weak self] in
self?.doSomething()
}
2. Принудительное развертывание Optional
Это очевидно, но мы все еще часто видим это в коде:
let name: String? = getName() print(name!) // Crashes if nil
Даже «безопасные» места могут подвести вас — например, повторное использование ячеек в UITableView.
Вместо этого используйте guard let или if let. Никогда не доверяйте данным слепо.
3. Неявно разворачиваемые Optional (String!)
Они кажутся удобными. Но они вызывают сбой, как и !, если не настроены правильно.
var token: String! print(token.count) // If token is nil, boom.
По умолчанию используется ?. Используйте ! только в том случае, если вы абсолютно уверены, что он инициализирован перед использованием (например, инжектирован через сториборд).
4. Не помеченные как final классы
По умолчанию каждый класс в Swift может быть подклассом. Это может привести к снижению производительности из-за динамической диспетчеризации.
Используйте final, когда подклассы не нужны. Компилятор будет оптимизировать код лучше.
final class UserManager {
// Now faster method calls, no subclassing allowed
}
5. Отсутствие weak у делегатов
Классическая ошибка в конфигурациях MVC или MVVM.
protocol MyDelegate: AnyObject {
func didUpdate()
}
class MyController {
var delegate: MyDelegate? // ⚠️ Should be weak
}
Всегда объявляйте свойства делегатов как weak, чтобы избежать циклов удержания:
weak var delegate: MyDelegate?
6. Бездумное использование DispatchQueue.main.async
Да, вам нужно обновлять пользовательский интерфейс в основном потоке. Но если вы слепо обернете все в DispatchQueue.main.async, вы рискуете столкнуться с условиями гонки или задержками обновлений.
DispatchQueue.main.async {
self.label.text = "Updated"
}
Используйте это только в том случае, если вы уверены, что уже не находитесь в главном потоке.
7. Путаница между типами значений и ссылок
Структуры (такие как User) копируются при присваивании. Классы совместно используются по ссылке.
struct User {
var name: String
}
var a = User(name: "Abhinav")
var b = a
b.name = "Singh"
print(a.name) // Still "Abhinav"
Знайте, когда вам нужна неизменяемость (структура) и когда — общее состояние (класс). Их смешивание приводит к неприятным ошибкам.
8. Неправильное использование Codable
Codable в Swift — это замечательно… до тех пор, пока не изменится структура JSON и декодирование без предупреждения не завершится с ошибкой.
struct User: Codable { let id: Int let name: String }
Если бэкэнд отправит user_id вместо id, декодирование завершится сбоем.
Используйте CodingKeys явно, когда поля различаются:
enum CodingKeys: String, CodingKey {
case id = "user_id"
case name
}
9. Неправильное использование @Published в SwiftUI/Combine
Простое добавление @Published не вызывает обновление пользовательского интерфейса вне основного потока или если обновление происходит косвенно.
@Published var name: String = ""
DispatchQueue.global().async {
self.name = "New" // ⚠️ No UI update
}
Всегда обновляйте свойства @Published в главном потоке:
DispatchQueue.main.async {
self.name = "New"
}
10. Путаница между Any и AnyObject
Они кажутся похожими, но на самом деле это не так. Any означает любой тип. AnyObject означает любой тип класса.
func handle(data: Any) { ... } // Can be Int, String, Class, etc.
func handleObject(data: AnyObject) { ... } // Only class instances
Будьте точны в том, что вы используете. Использование Any может привести к путанице при преобразовании типов во время выполнения.
Пример: ошибочная настройка
Давайте визуализируем типичную настройку утечки памяти:
[ViewController] --> owns --> [ViewModel] --> owns closure --> [ViewController]
Если это замыкание захватывает self → цикл удержания → ViewController никогда не деаллоцируется.
Исправьте с помощью [weak self] в закрытии, или лучше: сделайте так, чтобы владелец замыкания не владел источником.
Заключительные мысли
Swift — мощный язык, но он не является безошибочным.
Компилятор помогает, но везде есть скрытые ловушки. Большинство из этих ловушек не приведут к сбою в первый день — они проявятся через несколько недель, когда ваше приложение начнет вести себя странно или излишне потреблять память.
Будьте параноиком на раннем этапе. Будьте предсказуемы позже.
И помните.
То, что код компилируется, не означает, что он безопасен.
-
Аналитика магазинов2 недели назад
Мобильный рынок Ближнего Востока: исследование Bidease и Sensor Tower выявляет драйверы роста
-
Интегрированные среды разработки3 недели назад
Chad: The Brainrot IDE — дикая среда разработки с играми и развлечениями
-
Новости4 недели назад
Видео и подкасты о мобильной разработке 2025.45
-
Новости3 недели назад
Видео и подкасты о мобильной разработке 2025.46

