Как выполнить сетевой запрос в iOS с помощью URLSession?

Ответ

URLSession — это основной фреймворк iOS для выполнения сетевых запросов. Он поддерживает различные типы задач (data, download, upload) и предоставляет мощные возможности конфигурации и делегирования.

Базовый GET-запрос с обработкой JSON:

// 1. Определяем endpoint
let url = URL(string: "https://api.example.com/users")!

// 2. Создаем Data Task
let task = URLSession.shared.dataTask(with: url) { data, response, error in
    // 3. Обрабатываем ошибку сети
    if let error = error {
        print("Network error: (error)")
        return
    }

    // 4. Проверяем HTTP-статус ответа
    guard let httpResponse = response as? HTTPURLResponse,
          (200...299).contains(httpResponse.statusCode) else {
        print("Server returned an error")
        return
    }

    // 5. Проверяем наличие данных
    guard let data = data else { return }

    // 6. Декодируем JSON в модель (используя Codable)
    do {
        let users = try JSONDecoder().decode([User].self, from: data)
        // 7. Обновляем UI в главном потоке
        DispatchQueue.main.async {
            self.updateUI(with: users)
        }
    } catch {
        print("JSON decoding failed: (error)")
    }
}

// 8. Запускаем задачу (задачи по умолчанию приостановлены)
task.resume()

Расширенные возможности:

  • Создание запроса (URLRequest): Позволяет задать метод (POST, PUT), заголовки и тело запроса.

    var request = URLRequest(url: url)
    request.httpMethod = "POST"
    request.setValue("application/json", forHTTPHeaderField: "Content-Type")
    request.httpBody = try? JSONEncoder().encode(postData)
  • Кастомная конфигурация (URLSessionConfiguration): Можно настроить таймауты, политики кэширования, использовать фоновую сессию.

    let config = URLSessionConfiguration.default
    config.timeoutIntervalForRequest = 30
    config.requestCachePolicy = .reloadIgnoringLocalCacheData
    let session = URLSession(configuration: config)
  • Современные подходы:

    • Async/await (iOS 15+): Упрощает код, избавляя от completion handlers.
      let (data, response) = try await URLSession.shared.data(from: url)
    • Combine: Позволяет работать с сетевыми запросами как с издателями (publishers).

Ответ 18+ 🔞

Ну, смотри, вот эта штука URLSession — это типа твой главный по тарелочкам в iOS, когда надо в интернет сходить. Он умеет и данные скачать, и файлы, и загрузить что-то. В общем, штука мощная, с кучей настроек и делегатов, если хочешь контролировать каждый чих.

Вот как выглядит простейший запрос, чтобы что-то получить (GET) и JSON распарсить:

// 1. Куда идём? Тыкаем пальцем в URL
let url = URL(string: "https://api.example.com/users")!

// 2. Готовим задачу на получение данных
let task = URLSession.shared.dataTask(with: url) { data, response, error in
    // 3. Сначала смотрим, не облажался ли интернет
    if let error = error {
        print("Сеть, блядь, сдохла: (error)")
        return
    }

    // 4. А теперь проверяем, не послал ли нам сервер какую-нибудь хуйню вместо ответа
    guard let httpResponse = response as? HTTPURLResponse,
          (200...299).contains(httpResponse.statusCode) else {
        print("Сервер вернул какую-то дичь, не 200")
        return
    }

    // 5. Данные-то вообще пришли? Или пустой пакет?
    guard let data = data else { return }

    // 6. Пытаемся выковырять из JSON'а наших юзеров (спасибо, Codable!)
    do {
        let users = try JSONDecoder().decode([User].self, from: data)
        // 7. ВСЁ, ДАННЫЕ ЕСТЬ! Но UI обновлять надо в главном потоке, а то приложение взвоет.
        DispatchQueue.main.async {
            self.updateUI(with: users)
        }
    } catch {
        print("Не, ну это пиздец, JSON развалился: (error)")
    }
}

// 8. ВАЖНО! Задача создаётся приостановленной. Надо её, блядь, ПУСТИТЬ!
task.resume()

А если хочется покруче, то вот на что ещё способен этот зверь:

  • Создание своего запроса (URLRequest): Чтобы не просто GET'ом тыкать, а отправить POST с телом и хидерами.

    var request = URLRequest(url: url)
    request.httpMethod = "POST" // Теперь мы не просим, а отправляем!
    request.setValue("application/json", forHTTPHeaderField: "Content-Type") // Говорим, что шлём JSON
    request.httpBody = try? JSONEncoder().encode(postData) // А вот и сам JSON
  • Своя конфигурация (URLSessionConfiguration): Хочешь, чтобы запросы не кэшировались или таймаут был побольше? Легко!

    let config = URLSessionConfiguration.default
    config.timeoutIntervalForRequest = 30 // Ждём ответа 30 секунд, а не вечность
    config.requestCachePolicy = .reloadIgnoringLocalCacheData // Нахуй кэш, каждый раз свежее!
    let session = URLSession(configuration: config) // Сессия с нашей конфигурацией
  • Современные приблуды:

    • Async/await (iOS 15+): О, это просто песня, ебать мои старые костыли! Убирает эти вечные completion handlers.
      let (data, response) = try await URLSession.shared.data(from: url) // Красота же!
    • Combine: Для любителей реактивного подхода. Запрос становится издателем, на который можно подписываться.
      // Тут уже магия Combine начинается, но идея та же