> Как организовать сетевые вызовы в iOS проекте (iOS, Swift)
Уровень: senior · Роль: mobile · Категория: Технические вопросы
Компании: Bip.ru
Стек: iOS, Swift
> Пример ответа
Короткий ответ
Сетевые вызовы в iOS организуются через URLSession с слоем абстракции: протокол Endpoint (описание запроса), сервис (выполнение и обработка), модели DTO и маппинг в доменные сущности. Для реактивных потоков используют async/await или Combine. Кэширование - через URLCache или отдельный слой. Типичная структура: NetworkClient → Endpoint → Service → Repository → ViewModel. Важно учитывать тестируемость через протоколы и инъекцию зависимостей.
Подробное объяснение
Сетевой слой в iOS состоит из нескольких уровней:
-
Транспортный уровень - URLSession, настройка конфигурации (timeout, cache policy, HTTP headers). Для сложных проектов - обёртка над URLSession (NetworkClient), которая инкапсулирует логику декодирования, обработки ошибок, ретраев.
-
Описание запросов - протокол Endpoint (или APIRouter) с properties: baseURL, path, method, parameters, headers. Это позволяет типизировать запросы и избежать строковых ошибок.
-
Обработка ответов - декодирование через JSONDecoder (или Codable), маппинг DTO в доменные модели. Обработка ошибок: сетевые (timeout, no connection), HTTP-статусы, ошибки декодирования.
-
Асинхронность - современный подход: async/await с URLSession. Для реактивных архитектур - Combine (Future, PassthroughSubject) или сторонние библиотеки (Alamofire, Moya - но на собеседовании лучше показать понимание URLSession).
-
Кэширование - URLCache (по умолчанию), политики cachePolicy, ETag/Last-Modified. Для сложных кейсов - собственный кэш (CoreData, файловая система).
-
Тестируемость - протокол NetworkClientProtocol, моки URLProtocol или инъекция URLSession с mock-конфигурацией.
На практике
Для senior-позиции важно показать:
- Понимание жизненного цикла запроса: создание URLRequest, обработка redirects, authentication challenges.
- Управление конкурентностью: отмена запросов (Task cancellation), дедупликация одинаковых запросов, ограничение параллельных запросов (semaphore, операционные очереди).
- Обработка race conditions при обновлении UI после ответа.
- Стратегии ретраев: exponential backoff, jitter, ограничение количества попыток.
- Поддержка нескольких окружений (dev/stage/prod) через конфигурацию.
- Логирование запросов/ответов (для дебага) - без сторонних библиотек, через URLProtocol или делегаты URLSession.
Пример кода
SWIFTprotocol Endpoint {var baseURL: URL { get }var path: String { get }var method: HTTPMethod { get }var parameters: [String: Any]? { get }var headers: [String: String]? { get }}protocol NetworkClientProtocol {func send<T: Decodable>(_ endpoint: Endpoint) async throws -> T}final class NetworkClient: NetworkClientProtocol {private let session: URLSessionprivate let decoder: JSONDecoderinit(session: URLSession = .shared, decoder: JSONDecoder = JSONDecoder()) {self.session = sessionself.decoder = decoder}func send<T: Decodable>(_ endpoint: Endpoint) async throws -> T {var request = URLRequest(url: endpoint.baseURL.appendingPathComponent(endpoint.path))request.httpMethod = endpoint.method.rawValuerequest.allHTTPHeaderFields = endpoint.headersif let parameters = endpoint.parameters {request.httpBody = try JSONSerialization.data(withJSONObject: parameters)}let (data, response) = try await session.data(for: request)guard let httpResponse = response as? HTTPURLResponse else {throw NetworkError.invalidResponse}guard (200...299).contains(httpResponse.statusCode) else {throw NetworkError.serverError(statusCode: httpResponse.statusCode)}return try decoder.decode(T.self, from: data)}}// Пример использованияstruct UserEndpoint: Endpoint {let id: Intvar path: String { "/users/\(id)" }var method: HTTPMethod { .get }var parameters: [String: Any]? { nil }var headers: [String: String]? { ["Accept": "application/json"] }var baseURL: URL { URL(string: "https://api.example.com")! }}
Как отвечать на собеседовании
Начни с архитектуры: назови слои и их ответственность. Затем переходи к конкретике: URLSession, async/await, обработка ошибок. Покажи, что понимаешь trade-off между простотой URLSession и удобством сторонних библиотек. Упомяни тестируемость - это ключевой момент для senior. Если спросят про конкретный кейс (например, загрузка изображений), опиши кэширование, отмену, приоритизацию. Не углубляйся в детали реализации без запроса - сначала дай общую картину, потом отвечай на уточняющие вопросы.
Что проверяет интервьюер
- Понимание сетевого стека iOS, а не заучивание API.
- Умение проектировать абстракции: протоколы, зависимости, тестируемость.
- Знание конкурентности: async/await, отмена задач, гонки данных.
- Практический опыт: обработка ошибок, ретраи, кэширование.
- Способность объяснить trade-off: URLSession vs Alamofire, Codable vs manual parsing.
Типичные ошибки
- Использование Alamofire без объяснения, почему не URLSession.
- Отсутствие слоя абстракции: прямые вызовы URLSession в ViewController.
- Игнорирование обработки ошибок декодирования и сетевых ошибок отдельно.
- Непонимание отмены запросов при уходе с экрана.
- Отсутствие тестов сетевого слоя (моки, URLProtocol).
- Смешивание DTO и доменных моделей в одном типе.
> Похожие задачи по mobile
Как решить проблему тестирования синглтона с использованием моков
В чем разница фабрики и билдера
Может ли дедлок возникать между задачами на разных очередях
Что происходит при состояниях гонки, дедлоках, инверсии приоритетов, взрыве потоков, голодании и лайфлоке
> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?
Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью