iOS-разработчик
80 задач. Условие и варианты ответа открыты всем; проверка, подсказка и разбор — в клубе.
Swift: типы, опционалы и ARC
- Присваивание структуры другой переменной: что напечатает print
- Форсированный разворот результата Int(String) на данных из ответа сервера
- guard let с дополнительным условием: результат для пустой строки и для nil
- Сервис хранит completion, экран закрыли — почему ViewModel не освобождается
- Структура с полем-классом: что увидит первая копия после изменения второй
- Замыкание печатает захваченную переменную, изменённую после его создания
- Экран закрыт, но tick продолжает срабатывать и deinit не вызывается
- Метод из расширения протокола: какой из двух вызовов уйдёт в реализацию структуры
UIKit и SwiftUI: экраны и состояние
- Баланс на экране профиля не обновляется при возврате назад
- Вью с констрейнтами уехало в угол, а консоль полна конфликтов Auto Layout
- При скролле ленты у части ячеек остаётся чужая плашка «Скидка»
- Ввод в поиске сбрасывает список: как объявлена ViewModel в SwiftUI-вью
- ForEach с id по индексу: что ломается при вставке элемента в начало списка
- Значение проставляют в лейбл следующего экрана до его показа — падение
- Таймер раз в секунду перерисовывает весь экран заказа вместе с картой
- Modifying state during view update: почему нельзя присваивать @State внутри body
Сеть, данные и конкурентность
- Обновление таблицы прямо в completion URLSession
- Ключи snake_case в JSON и camelCase в модели Decodable
- Сервер ответил 500, а ветка обработки ошибки не сработала
- Три независимых запроса подряд через await: экран собирается почти секунду
- DispatchQueue.main.sync в методе обновления заголовка
- Объекты Core Data перебираются на фоновой очереди
- Словарь-кеш пишется из нескольких очередей: чем чинить гонку
- В поиске по мере ввода иногда остаются результаты предыдущего запроса
Архитектура, тесты и релиз
- Разделение ответственности между View и ViewModel в MVVM
- Экран сам решает, что открыть следующим: чем это мешает при новых точках входа
- У разработчика собирается, на CI падает: что не так с зависимостями
- ViewModel создаёт сервис внутри себя: почему это ломает тесты
- Тест на асинхронную загрузку всегда зелёный
- Память растёт после каждого открытия экрана карты: чем искать причину
- Через два часа после релиза crash-free упал с 99.6% до 94%
- Модули Catalog и Checkout ссылаются друг на друга: SPM не собирает цикл
Swift Concurrency: Task, акторы и MainActor
- Кнопка «Обновить» не компилируется: async call in a function that does not support concurrency
- Фиолетовое предупреждение Publishing changes from background threads is not allowed
- Задержка поиска сделана через Thread.sleep внутри Task
- Джун боится, что await на главном акторе заморозит экран на время запроса
- Фото галереи после загрузки в TaskGroup встают в случайном порядке
- Разбор прайса на 40 МБ в Task {} всё равно замораживает интерфейс
- Экспорт 10 000 заказов продолжается после нажатия «Отмена»
- Обёртка над делегатом геолокации падает с SWIFT TASK CONTINUATION MISUSE
- Опрос статуса доставки продолжается после ухода с экрана заказа
- В Swift 6 передача класса корзины в Task.detached перестала компилироваться
- Синхронная обёртка над async-запросом через DispatchSemaphore иногда зависает навсегда
- Актор токенов делает три запроса обновления, хотя данные в нём защищены
Combine: издатели, подписки и операторы
- Подписка на изменения корзины через sink получает только первое значение
- Таблица обновляется из цепочки dataTaskPublisher с задержкой и предупреждениями
- На ввод слова «кроссовки» поиск отправил 9 запросов
- Экран профиля, открытый после входа, не знает, что пользователь авторизован
- В sink на $query свойство query ещё содержит старый текст
- Запрос в Future уходит на сервер, хотя на издатель никто не подписался
- Две подписки на один издатель профиля дают два одинаковых запроса
- Кнопка «Оформить» не активируется, пока пользователь не тронет чекбокс согласия
- ViewModel с подпиской на таймер не освобождается после закрытия экрана
- После одной сетевой ошибки поиск перестаёт реагировать на ввод
- Заменили sink на assign(to:on: self) — ViewModel всё равно не освобождается
- Добавили subscribe(on: main) — UI всё равно обновляется из фона
Хранение данных: Core Data, Keychain и UserDefaults
- Токен доступа к банковскому API хранится в UserDefaults
- Заметки видны до перезапуска приложения, а после — пропадают
- Виджет баланса всегда показывает ноль, хотя приложение сохранило баланс
- Каталог на 6 МБ в UserDefaults — холодный старт стал на секунду дольше
- После удаления и повторной установки приложение сразу открывается залогиненным
- После обновления приложение падает на старте только у старых пользователей
- Синхронизация сохранила 300 заказов в фоне, но список на экране не обновился
- Сохранение заметки падает с ошибкой конфликта слияния после фоновой синхронизации
- Список 500 заказов с именем покупателя грузится 3 секунды
- После NSBatchDeleteRequest удалённые сообщения остаются в списке чата
- Фоновое обновление не может прочитать токен из Keychain: errSecInteractionNotAllowed
- После каждой синхронизации товары в каталоге дублируются
Производительность и Instruments
- Лента товаров дёргается при скролле — с какого инструмента начать
- На симуляторе в Debug открытие экрана занимает 900 мс, у пользователей — жалоб нет
- Отчёт о падении при запуске с кодом 0x8badf00d
- Каждая ячейка ленты создаётся через init — память растёт при прокрутке
- Галерея из 20 миниатюр 80×80 занимает почти гигабайт памяти
- Time Profiler показывает DateFormatter.init в топе при скролле истории заказов
- Карточки с тенью тормозят скролл, хотя cellForRowAt выполняется быстро
- Leaks ничего не находит, а память растёт с каждой открытой карточкой товара
- Нужно увидеть в Instruments, сколько длится разбор ответа каталога среди других событий
- Таймер обратного отсчёта перерисовывает весь экран каталога раз в секунду
- 60 динамических фреймворков из CocoaPods — холодный запуск больше двух секунд
- На iPhone разработчика всё плавно, а в Xcode Organizer растёт доля зависаний
