Avatar ·

Как выполнить HTTP запрос в Swift с использованием URLSession? (iOS)

Всем привет! Я новичок в Swift и iOS разработке. Пишу своё первое приложение, которое должно получать данные с сервера по HTTP. Я прочитал, что раньше использовали NSURLConnection, но сейчас это устарело. Пытаюсь разобраться с URLSession, но у меня ничего не работает. Вот мой код: ```swift import UIKit class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() let url = URL(string: "https://jsonplaceholder.typicode.com/posts/1") let request = URLRequest(url: url!) let session = URLSession.shared let task = session.dataTask(with: request) task.resume() } } ``` Приложение запускается, но ничего не происходит — данные не приходят, нет ошибок, консоль пустая. Я не понимаю, как обработать ответ сервера. Нужно ли как-то парсить JSON? И как вообще получить данные в переменную, чтобы потом вывести их в UILabel или TableView? Подскажите, пожалуйста, правильный способ сделать HTTP запрос в Swift и обработать ответ. Заранее спасибо! <<>>

Правильный способ выполнения HTTP запроса в Swift с URLSession

Ваша проблема в том, что вы создали задачу (task), но не указали, что делать с ответом. Метод dataTask(with:) требует completion handler, который обрабатывает результат. Вот полное и корректное решение.

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        
        // 1. Создаем URL
        guard let url = URL(string: "https://jsonplaceholder.typicode.com/posts/1") else {
            print("Неверный URL")
            return
        }
        
        // 2. Создаем запрос (опционально, можно использовать URL напрямую)
        var request = URLRequest(url: url)
        request.httpMethod = "GET" // GET по умолчанию, но явно указываем
        request.setValue("application/json", forHTTPHeaderField: "Accept") // ожидаем JSON
        
        // 3. Создаем сессию
        let session = URLSession.shared
        
        // 4. Создаем задачу с completion handler
        let task = session.dataTask(with: request) { data, response, error in
            // Проверяем ошибки
            if let error = error {
                print("Ошибка запроса: \(error.localizedDescription)")
                return
            }
            
            // Проверяем HTTP статус
            guard let httpResponse = response as? HTTPURLResponse,
                  (200...299).contains(httpResponse.statusCode) else {
                print("Неверный HTTP статус: \((response as? HTTPURLResponse)?.statusCode ?? 0)")
                return
            }
            
            // Проверяем, что данные есть
            guard let data = data else {
                print("Нет данных в ответе")
                return
            }
            
            // 5. Парсим JSON
            do {
                if let json = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] {
                    // Работаем с JSON
                    print("Полученные данные:")
                    for (key, value) in json {
                        print("\(key): \(value)")
                    }
                    
                    // Обновляем UI в главном потоке
                    DispatchQueue.main.async {
                        // Здесь можно обновить UILabel или TableView
                        // Например: self.myLabel.text = json["title"] as? String
                    }
                }
            } catch {
                print("Ошибка парсинга JSON: \(error.localizedDescription)")
            }
        }
        
        // 6. Запускаем задачу
        task.resume()
    }
}

Ключевые моменты:

  • Completion handler — обязательный параметр, который получает три значения: data (тело ответа), response (метаданные ответа), error (ошибка).
  • Проверка ошибок — всегда проверяйте error и HTTP статус код (200-299 успех).
  • Парсинг JSON — используйте JSONSerialization или современные Codable протоколы.
  • Главный поток — обновление UI должно выполняться в главном потоке через DispatchQueue.main.async.

Более современный подход с Codable (Swift 4+):

// Модель данных
struct Post: Codable {
    let userId: Int
    let id: Int
    let title: String
    let body: String
}

// Запрос с Codable
let task = session.dataTask(with: request) { data, response, error in
    guard let data = data, error == nil else { return }
    
    do {
        let post = try JSONDecoder().decode(Post.self, from: data)
        print("Title: \(post.title)")
        print("Body: \(post.body)")
    } catch {
        print("Ошибка декодирования: \(error)")
    }
}
task.resume()

Этот подход безопаснее и читаемее. Всегда используйте guard let для безопасного извлечения опциональных значений и не забывайте запускать задачу через resume().

<<>>

Альтернативный подход с использованием async/await (Swift 5.5+)

Если вы используете современные версии Swift (Xcode 13+), можно упростить код с помощью асинхронных функций. Это делает код более линейным и понятным.

import UIKit

class ViewController: UIViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        Task {
            await fetchData()
        }
    }
    
    func fetchData() async {
        guard let url = URL(string: "https://jsonplaceholder.typicode.com/posts/1") else {
            print("Неверный URL")
            return
        }
        
        do {
            let (data, response) = try await URLSession.shared.data(from: url)
            
            guard let httpResponse = response as? HTTPURLResponse,
                  (200...299).contains(httpResponse.statusCode) else {
                print("Ошибка HTTP")
                return
            }
            
            // Используем Codable
            let post = try JSONDecoder().decode(Post.self, from: data)
            print("Title: \(post.title)")
            
            // Обновляем UI
            await MainActor.run {
                // self.myLabel.text = post.title
            }
        } catch {
            print("Ошибка: \(error.localizedDescription)")
        }
    }
}

Преимущества этого подхода:

  • Нет вложенных completion handler'ов — код читается сверху вниз
  • Автоматическая обработка потоков (MainActor для UI)
  • Лучшая обработка ошибок через try/catch

Обратите внимание: для использования async/await ваше приложение должно поддерживать iOS 13+, macOS 10.15+ и выше. Это рекомендуемый подход для новых проектов.