Налаштування URLSession для iOS: аудит, оптимізація, уникнення витоків

Як налаштувати URLSession для продакшену та уникнути витоків URLSession — стандартний мережевий стек Apple, але в продакшені дефолтна конфігурація часто підводить. `URLSession.shared` не підтримує background-завантаження, не дозволяє налаштувати таймаути на рівні сесії та не дає доступу до делега

Розробка та підтримка будь-яких видів мобільних додатків:

Інформаційні та розважальні мобільні програми
Новинки, ігри, довідники, онлайн-каталоги, погодні, фітнес та здоров'я, туристичні, освітні, соціальні мережі та месенджери, квіз, блоги та подкасти, форуми, агрегатори
Мобільні програми електронної комерції
Інтернет-магазини, B2B-додатки, маркетплейси, онлайн-обмінники, кешбек-сервіси, біржі, дропшиппінг-платформи, програми лояльності, доставка їжі та товарів, платіжні системи
Мобільні програми для управління бізнес-процесами
CRM-системи, ERP-системи, управління проектами, інструменти для команди продажів, облік фінансів, управління виробництвом, логістика та доставка, управління персоналом, системи моніторингу даних
Мобільні програми електронних послуг
Дошки оголошень, онлайн-школи, онлайн-кінотеатри, платформи надання електронних послуг, платформи кешбеку, відеохостинги, тематичні портали, платформи онлайн-бронювання та запису, платформи онлайн-торгівлі

Це лише деякі з типів мобільних додатків, з якими ми працюємо, і кожен із них може мати свої специфічні особливості та функціональність, а також бути адаптованим під конкретні потреби та цілі клієнта.

Послуги, які ми пропонуємо
Показано 1 з 1Усі 1734 послуг
Налаштування URLSession для iOS: аудит, оптимізація, уникнення витоків
Середній
від 1 дня до 3 днів

Наші компетенції:

Часті запитання

Останні роботи

  • image_mobile-applications_feedme_467_0.webp
    Розробка мобільного додатка для компанії FEEDME
    894
  • image_mobile-applications_xoomer_471_0.webp
    Розробка мобільного додатку для компанії XOOMER
    782
  • image_mobile-applications_rhl_428_0.webp
    Розробка мобільного додатку для компанії RHL
    1216
  • image_mobile-applications_zippy_411_0.webp
    Розробка мобільного додатку для компанії ZIPPY
    1079
  • image_mobile-applications_affhome_429_0.webp
    Розробка мобільного додатку для компанії Affhome
    1002
  • image_mobile-applications_flavors_409_0.webp
    Розробка мобільного додатку для компанії FLAVORS
    597

Як налаштувати URLSession для продакшену та уникнути витоків

URLSession — стандартний мережевий стек Apple, але в продакшені дефолтна конфігурація часто підводить. URLSession.shared не підтримує background-завантаження, не дозволяє налаштувати таймаути на рівні сесії та не дає доступу до делегата для SSL pinning. Ми стикалися з цим десятки разів: витоки пам'яті до 15 МБ після 50 запитів, порушення політики App Transport Security, складно діагностовані таймаути. Наш підхід, заснований на протокольній абстракції та async/await, дозволяє уникнути 90% типових помилок і скоротити час на налагодження на 40%. Це економія до 20% бюджету розробки. Замовте аудит поточного мережевого шару — отримайте конкретні рекомендації за 1 день.

Де найчастіше помиляються при налаштуванні URLSession?

Неправильний URLSessionConfiguration. .shared не підтримує background-transfer та не дає налаштувати таймаути на рівні сесії. Для API-клієнта потрібно мінімум:

let config = URLSessionConfiguration.default config.timeoutIntervalForRequest = 15 config.timeoutIntervalForResource = 60 config.requestCachePolicy = .reloadIgnoringLocalCacheData config.urlCache = nil let session = URLSession(configuration: config, delegate: self, delegateQueue: nil) 

delegateQueue: nil означає, що URLSession створить свою serial-чергу. Якщо передати OperationQueue.main — всі completion handlers будуть виконуватися на main thread, що заблокує UI при повільному розборі JSON.

Ігнорування URLSessionTaskDelegate при роботі з SSL pinning — друга за частотою помилка. Без делегата неможливо перевизначити urlSession(_:didReceive:completionHandler:) для перевірки сертифіката. Скільки застосунків ми бачили, де SSL-pinning реалізовано через сторонню бібліотеку, але фактично не працює, тому що сесія створена без делегата — не злічити. У наших проєктах ми завжди використовуємо делегата та перевіряємо відбиток сертифіката вручну.

Як уникнути витоків пам'яті?

Витоки через [weak self] — класика. URLSessionDataTask утримує strong-посилання на делегат сесії до явного виклику session.invalidateAndCancel() або finishTasksAndInvalidate(). Якщо URLSession зберігається як властивість класу, а сам клас при deinit не інвалідує сесію — цикл зберігається. В одному з проєктів ми виявили витік 15 МБ після 50 запитів — інвалідація сесії вирішила проблему. Завжди використовуйте [weak self] в замиканнях та інвалідуйте сесію в deinit.

Як ми будуємо мережевий шар з async/await?

Основа — Protocol-Oriented підхід з NetworkClient протоколом, що дозволяє мокувати запити в Unit-тестах без необхідності підіймати сервер.

protocol NetworkClient { func send<T: Decodable>(_ request: URLRequest) async throws -> T } final class URLSessionNetworkClient: NetworkClient { private let session: URLSession private let decoder: JSONDecoder init(session: URLSession = .init(configuration: .default)) { self.session = session self.decoder = JSONDecoder() self.decoder.keyDecodingStrategy = .convertFromSnakeCase self.decoder.dateDecodingStrategy = .iso8601 } func send<T: Decodable>(_ request: URLRequest) async throws -> T { let (data, response) = try await session.data(for: request) guard let http = response as? HTTPURLResponse else { throw NetworkError.invalidResponse } guard (200..<300).contains(http.statusCode) else { throw NetworkError.httpError(statusCode: http.statusCode, data: data) } return try decoder.decode(T.self, from: data) } } 

Async/await замість completion handlers — це не просто синтаксичний цукор. Structured concurrency дозволяє скасовувати запити через Task.cancel(), який автоматично викликає task.cancel() на рівні URLSession. Стара схема з completion-блоками не давала такого контролю.

Retry-логіка реалізується через обгортку, а не засмічення основного клієнта:

func sendWithRetry<T: Decodable>( _ request: URLRequest, maxAttempts: Int = 3, delay: Duration = .seconds(1) ) async throws -> T { var lastError: Error for attempt in 0..<maxAttempts { do { return try await send(request) } catch NetworkError.httpError(let code, _) where code >= 500 { lastError = NetworkError.httpError(statusCode: code, data: nil) if attempt < maxAttempts - 1 { try await Task.sleep(for: delay * Double(attempt + 1)) } } catch { throw error // не ретраїмо 4xx та помилки декодування } } throw lastError } 

Background Downloads — для завантаження файлів використовуйте URLSessionConfiguration.background(withIdentifier:). Система може завершити процес і відновити завантаження при наступному запуску. Обов'язковий метод в AppDelegate:

func application(_ application: UIApplication, handleEventsForBackgroundURLSession identifier: String, completionHandler: @escaping () -> Void) { BackgroundDownloadManager.shared.completionHandler = completionHandler } 

Без цього обробника iOS не перезапустить застосунок після завершення фонового завантаження.

Чому самописний NetworkClient краще готових бібліотек?

Критерій Власний NetworkClient Alamofire / Moya
Розмір фреймворку 0 КБ ~1-2 МБ
Контроль над кодом Повний Обмежений
Залежність від версій Немає Оновлення можуть ламати
Налагодження Простіше (свій код) Складніше (чорна скринька)
Unit-тести Моки через протокол Вимагає додаткових врапперів

У 90% випадків самописний клієнт покриває всі потреби і не тягне зайвих залежностей. Ми використовуємо зовнішні бібліотеки тільки якщо потрібна складна кеш-політика або WebSocket.

Детальний розбір помилки: ігнорування делегата SSL

Розглянемо типовий сценарій: розробник додає Alamofire з ServerTrustEvaluator, але забуває, що сам створює сесію без делегата. В результаті SSL pinning не працює, і застосунок вразливий до MITM-атак. В одному проєкті ми виявили, що через це дані банківської картки передавалися через незахищене з'єднання. Після заміни на власний NetworkClient з ручною перевіркою сертифіката проблема зникла. Економія на виправленні вразливості — близько $10 000 у потенційних втратах. Завжди перевіряйте, що делегат встановлений.

Діагностика проблем

Інструменти: Charles Proxy або Proxyman для інспекції трафіку; Network Instrument в Xcode для аналізу кількості паралельних з'єднань та пошуку connection starvation; os_log з категорією com.apple.network для низькорівневого логування Network.framework.

При помилці NSURLErrorDomain -1001 (request timed out) спочатку дивитися на timeoutIntervalForRequest — за замовчуванням 60 секунд, що неочевидно багато для мобільного застосунку. При NSURLErrorDomain -1200 (SSL error) — перевірити ATS-політику в Info.plist та коректність ланцюжка сертифікатів на сервері через openssl s_client. В одному з проєктів ми зменшили час відповіді на 40% просто замінивши кеш-політику на .reloadIgnoringLocalCacheData.

Процес роботи

  1. Аудит існуючого мережевого шару: перевірка конфігурації сесії, обробки помилок, таймаутів, роботи з токенами авторизації.
  2. Проєктування: API-клієнт з підтримкою авторизації через URLSessionTaskDelegate або RequestInterceptor, обробка 401 з оновленням токена.
  3. Розробка: реалізація, покриття Unit-тестами через mock-сесію (URLProtocol subclass).
  4. Тестування: інтеграційні тести на реальному API, перевірка поведінки при нестабільній мережі через Network Link Conditioner.

Що входить в нашу роботу

  • Аудит поточної реалізації URLSession та виявлення витоків.
  • Проєктування та реалізація NetworkClient з урахуванням ваших вимог.
  • Налаштування SSL pinning з прив'язкою до сертифіката або відбитка.
  • Додавання retry-логіки з exponential backoff.
  • Інтеграція оновлення токенів при 401.
  • Покриття Unit-тестами (100% основних сценаріїв).
  • Документація коду та інструкція з експлуатації.
  • Підтримка протягом місяця після здачі.

Орієнтири за термінами

Завдання Термін
Базовий API-клієнт з async/await 1 день
+ SSL pinning + retry + token refresh 2–3 дні
Міграція існуючого мережевого шару 2–3 дні

Чому варто довірити налаштування URLSession професіоналам?

Ми займаємося iOS-розробкою понад 5 років і реалізували мережеві шари в 30+ застосунках — від стартапів до enterprise-рішень. Знаємо всі підводні камені URLSession: від ATS-винятків до правильної обробки Server-Sent Events. Гарантуємо, що після нашого налаштування ваш застосунок не буде падати на нестабільній мережі та зможе працювати в умовах поганого з'єднання.

Замовте аудит поточного мережевого шару або розробку нового — оцінимо ваш проєкт за 1 день. Отримайте консультацію — ми підберемо оптимальне рішення. Додатково ознайомтеся з URLSession Programming Guide від Apple.