Как выполнить HTTP запрос в Swift с использованием URLSession? (iOS)
Правильный способ выполнения 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+ и выше. Это рекомендуемый подход для новых проектов.
Ответов пока нет.
Войдите чтобы оставить ответ