Как выполнить HTTP-запрос в Swift: пошаговое руководство для iOS-разработчиков
Основная проблема: вы не обрабатываете ответ и не извлекаете данные
В вашем коде вы просто печатаете объект data, который может быть nil даже при успешном запросе. Нужно правильно обработать замыкание и преобразовать данные в строку.
Правильный минимальный GET-запрос
import Foundation
let url = URL(string: "https://jsonplaceholder.typicode.com/posts/1")!
let task = URLSession.shared.dataTask(with: url) { data, response, error in
// 1. Проверяем ошибки сети
if let error = error {
print("Ошибка запроса: \(error.localizedDescription)")
return
}
// 2. Проверяем HTTP-статус ответа
guard let httpResponse = response as? HTTPURLResponse,
(200...299).contains(httpResponse.statusCode) else {
print("Ошибка сервера: неверный статус-код")
return
}
// 3. Проверяем, что данные есть
guard let data = data else {
print("Нет данных в ответе")
return
}
// 4. Преобразуем Data в строку
if let responseString = String(data: data, encoding: .utf8) {
print("Ответ сервера:\n\(responseString)")
} else {
print("Не удалось декодировать данные в строку")
}
}
task.resume()
Разбор кода по шагам:
- Создание URL — всегда используйте
guard letили проверяйте опциональность, чтобы избежать force unwrap (!) - dataTask — асинхронный метод, который выполняется в фоновом потоке
- Обработка ошибок — проверяйте
error, статус-код и наличие данных - Преобразование данных —
Dataнужно декодировать в строку или JSON
Более современный подход с async/await (iOS 15+)
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("Ошибка сервера")
return
}
if let responseString = String(data: data, encoding: .utf8) {
print(responseString)
}
} catch {
print("Ошибка запроса: \(error.localizedDescription)")
}
}
// Вызов в асинхронном контексте
Task {
await fetchData()
}
Работа с JSON (самый частый случай)
struct User: Codable {
let id: Int
let name: String
let email: String
}
func fetchUser() {
let url = URL(string: "https://jsonplaceholder.typicode.com/users/1")!
URLSession.shared.dataTask(with: url) { data, _, error in
guard let data = data, error == nil else {
print("Ошибка: \(error?.localizedDescription ?? "неизвестная")")
return
}
do {
let user = try JSONDecoder().decode(User.self, from: data)
print("Пользователь: \(user.name), email: \(user.email)")
} catch {
print("Ошибка декодирования JSON: \(error)")
}
}.resume()
}
Важные советы для новичков:
- Всегда добавляйте
Info.plistразрешение на HTTP (или используйте HTTPS) - Для UI-обновлений после запроса используйте
DispatchQueue.main.async - Не забывайте вызывать
resume()— без него запрос не начнётся - Используйте
URLSession.sharedдля простых запросов, кастомную сессию — для сложных
Почему ваш код не работал:
Вы печатали data как объект Data?. В консоли это отображается как nil, даже если данные есть. Нужно обязательно преобразовать Data в читаемый формат через String(data:encoding:) или JSONDecoder.
Альтернативный подход: используйте библиотеку Alamofire
Если вам нужно часто делать запросы и не хочется писать boilerplate-код, попробуйте популярную библиотеку Alamofire. Она сильно упрощает работу с сетью.
Установка через Swift Package Manager или CocoaPods:
// Пример GET-запроса с Alamofire
import Alamofire
AF.request("https://jsonplaceholder.typicode.com/posts/1").responseString { response in
switch response.result {
case .success(let value):
print("Ответ: \(value)")
case .failure(let error):
print("Ошибка: \(error)")
}
}
Для работы с JSON:
struct Post: Decodable {
let userId: Int
let id: Int
let title: String
let body: String
}
AF.request("https://jsonplaceholder.typicode.com/posts/1")
.responseDecodable(of: Post.self) { response in
if let post = response.value {
print("Пост: \(post.title)")
}
}
Преимущества Alamofire:
- Автоматическая обработка ошибок и статус-кодов
- Поддержка параметров, заголовков и кодирования
- Встроенное логирование запросов
- Простая загрузка/отправка файлов
Однако для учебных целей и простых проектов я рекомендую сначала освоить нативный URLSession — так вы лучше поймёте, как работают сетевые запросы под капотом.