Сетевое программирование на Swift: от сокетов до WebSocket

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Сетевое программирование на Swift: от простого к сложному

Когда вы впервые открываете Xcode и видите пустой проект, кажется, что до настоящей магии сетевого взаимодействия еще далеко. Но поверьте: сетевое программирование на Swift — это не rocket science, а вполне осязаемый инструмент, который превращает локальное приложение в часть глобального интернета. Сегодня мы разберем, как заставить ваше приложение «говорить» с серверами, обмениваться данными и делать это красиво.

Я покажу вам не просто сухие определения, а реальные сценарии из жизни iOS-разработчика. Вы узнаете, как работает сетевое взаимодействие Swift на низком уровне (сокеты) и на высоком (URLSession). А в конце — бонус: как подключить WebSocket для live-чата. Поехали!

Понимание основ: как устроены сети в мире Swift

Прежде чем писать код, давайте разберемся с концепциями. Сетевое программирование на Swift базируется на тех же принципах, что и в любом другом языке: клиент-серверная архитектура, протоколы TCP/UDP, IP-адреса и порты. Но есть нюанс — экосистема Apple предлагает свои фреймворки, которые делают жизнь разработчика проще.

Ключевые технологии для работы с сетью в Swift

  • URLSession — основной инструмент для HTTP/HTTPS запросов. Работает с REST API, загрузкой файлов, фоновыми задачами.
  • Network.framework — низкоуровневый доступ к сокетам, TCP/UDP. Появился в iOS 12, заменил старый CFNetwork.
  • WebSocket (URLSessionWebSocketTask) — для двусторонней связи в реальном времени.
  • CFStream — старый, но еще живой способ работы с потоками данных.

Лично я рекомендую начинать с URLSession — это как езда на автомобиле с автоматической коробкой передач. А когда захочется «механики» — переходите на Network.framework.

URLSession: ваш главный друг в сетевом программировании Swift

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

Базовый GET-запрос

Представьте, что ваше приложение должно показать список пользователей с сервера. Вот как это делается:

import Foundation

// 1. Создаем URL
guard let url = URL(string: "https://jsonplaceholder.typicode.com/users") else {
    fatalError("Invalid URL")
}

// 2. Создаем задачу
let task = URLSession.shared.dataTask(with: url) { data, response, error in
    // 3. Обрабатываем ошибки
    if let error = error {
        print("Ошибка: \(error.localizedDescription)")
        return
    }
    
    // 4. Проверяем ответ сервера
    guard let httpResponse = response as? HTTPURLResponse,
          (200...299).contains(httpResponse.statusCode) else {
        print("Неверный статус код")
        return
    }
    
    // 5. Работаем с данными
    if let data = data {
        do {
            let users = try JSONDecoder().decode([User].self, from: data)
            print("Получено \(users.count) пользователей")
        } catch {
            print("Ошибка парсинга: \(error)")
        }
    }
}

// 6. Запускаем задачу
task.resume()

Обратите внимание: task.resume() обязателен! Иначе запрос никогда не выполнится. Это частая ошибка новичков в сетевом программировании на Swift.

POST-запрос с телом

Теперь отправим данные на сервер:

func createUser(name: String, email: String) {
    guard let url = URL(string: "https://jsonplaceholder.typicode.com/users") else {
        return
    }
    
    var request = URLRequest(url: url)
    request.httpMethod = "POST"
    request.setValue("application/json", forHTTPHeaderField: "Content-Type")
    
    let body: [String: String] = ["name": name, "email": email]
    request.httpBody = try? JSONSerialization.data(withJSONObject: body)
    
    let task = URLSession.shared.dataTask(with: request) { data, response, error in
        guard let data = data, error == nil else {
            print("Ошибка: \(error?.localizedDescription ?? "Неизвестная")")
            return
        }
        
        if let json = try? JSONSerialization.jsonObject(with: data) as? [String: Any] {
            print("Создан пользователь: \(json)")
        }
    }
    
    task.resume()
}

Обратите внимание: в iOS сетевом программировании все запросы выполняются асинхронно. Это значит, что UI не блокируется во время загрузки данных.

Работа с сокетами на Swift: когда нужна полная свобода

Бывают ситуации, когда HTTP-запросов недостаточно. Например, вы пишете чат, онлайн-игру или приложение для управления IoT-устройствами. Тут на помощь приходят сокеты Swift.

Сокеты позволяют установить постоянное соединение между клиентом и сервером. Данные передаются в реальном времени без постоянных HTTP-рукопожатий.

TCP-клиент с помощью Network.framework

Напишем простой TCP-клиент, который подключается к серверу и отправляет сообщение:

import Network

class TCPClient {
    let connection: NWConnection
    
    init(host: String, port: UInt16) {
        let host = NWEndpoint.Host(host)
        let port = NWEndpoint.Port(rawValue: port)!
        
        connection = NWConnection(host: host, port: port, using: .tcp)
        
        connection.stateUpdateHandler = { state in
            switch state {
            case .ready:
                print("Подключение установлено")
                self.sendMessage("Hello, server!")
            case .failed(let error):
                print("Ошибка подключения: \(error)")
            default:
                break
            }
        }
        
        connection.start(queue: .global())
    }
    
    func sendMessage(_ message: String) {
        let data = message.data(using: .utf8)!
        connection.send(content: data, completion: .contentProcessed { error in
            if let error = error {
                print("Ошибка отправки: \(error)")
            } else {
                print("Сообщение отправлено")
            }
        })
    }
    
    func receive() {
        connection.receive(minimumIncompleteLength: 1, maximumLength: 1024) { data, _, _, error in
            if let data = data, !data.isEmpty {
                let message = String(data: data, encoding: .utf8) ?? "Некорректные данные"
                print("Получено: \(message)")
            }
            
            if error == nil {
                self.receive() // Продолжаем слушать
            }
        }
    }
}

// Использование
let client = TCPClient(host: "127.0.0.1", port: 8080)
client.receive()

Этот код демонстрирует сетевое программирование на Swift на низком уровне. Видите, как мы обрабатываем состояния подключения? В реальных проектах это критически важно для стабильности.

UDP-сокеты: когда скорость важнее надежности

UDP — это протокол без установления соединения. Он быстрее TCP, но не гарантирует доставку пак

Блоги

Рекомендаций по книгам