URLSession

Standard HTTP client API for iOS/macOS provided by Apple. Part of Foundation framework, achieving native high-performance HTTP communication. Built-in async/await support, HTTP/2 compatibility, background transfer, detailed configuration options, and cookie management.

HTTP ClientSwiftStandard LibraryFoundationiOSmacOS

GitHub Overview

swiftlang/swift

The Swift Programming Language

Stars69,178
Watchers2,433
Forks10,560
Created:October 23, 2015
Language:C++
License:Apache License 2.0

Topics

None

Star History

swiftlang/swift Star History
Data as of: 10/22/2025, 04:10 AM

Library

URLSession

Overview

URLSession is provided as part of the Swift Foundation framework as "a set of classes for configuring and managing network sessions." As the de facto standard HTTP client for Apple platforms, it supports network communication in iOS, macOS, watchOS, and tvOS applications. It enables asynchronous download and upload of data to and from endpoints identified by URLs, and comprehensively supports enterprise-level network features such as WebSocket communication, background downloads, and certificate pinning.

Details

URLSession 2025 edition provides modern asynchronous programming patterns through complete integration with Swift Concurrency (async/await), in addition to traditional callback-based APIs. With three main task types - URLSessionDataTask, URLSessionUploadTask, and URLSessionDownloadTask - it handles a wide range of network communication needs from basic HTTP requests to large file transfers. It provides advanced features that meet mobile application-specific requirements as standard, including background execution, App Transport Security (ATS), HTTP/2 support, and custom protocol support.

Key Features

  • Comprehensive Task Types: Diverse communication patterns including Data, Upload, Download, and WebSocket
  • Swift Concurrency Integration: Modern asynchronous programming with async/await
  • Background Processing: Continuous data transfer when app is inactive
  • Enhanced Security: ATS, certificate pinning, TLS 1.3 support
  • HTTP/2 & HTTP/3 Support: High-speed communication with latest protocols
  • Combine Framework Integration: Reactive programming pattern support

Pros and Cons

Pros

  • Complete integration and optimization as Apple platform standard
  • Excellent development experience through natural integration with Swift Concurrency
  • Rich background download and mobile-specific features
  • Standard compliance with security requirements for App Store review
  • Advanced support for latest protocols like WebSocket and HTTP/3
  • Memory management and performance optimization guaranteed by Apple

Cons

  • Limited to Apple platforms, unavailable on other operating systems
  • Complex for lightweight use cases requiring overly detailed configuration
  • Limited network logging during debugging
  • Constraints on customizability compared to third-party libraries
  • Increased learning cost due to coexistence with legacy APIs
  • Limited direct integration features with SwiftUI

Reference Pages

Code Examples

Basic Setup and Import

import Foundation
import Combine // When using Publisher

// async/await support for iOS 15+ / macOS 12+
@available(iOS 15.0, macOS 12.0, *)
class NetworkManager {
    static let shared = NetworkManager()
    
    private init() {}
    
    // Basic URLSession instance
    private let session = URLSession.shared
    
    // Custom configured URLSession
    private lazy var customSession: URLSession = {
        let config = URLSessionConfiguration.default
        config.timeoutIntervalForRequest = 30
        config.timeoutIntervalForResource = 60
        config.waitsForConnectivity = true
        
        return URLSession(configuration: config)
    }()
}

// Swift structures for responses
struct User: Codable {
    let id: Int
    let name: String
    let email: String
    let age: Int?
}

struct APIResponse<T: Codable>: Codable {
    let success: Bool
    let data: T
    let message: String
}

struct ErrorResponse: Codable {
    let error: String
    let code: Int
    let details: String?
}

Basic Requests (GET/POST/PUT/DELETE)

import Foundation

extension NetworkManager {
    
    // MARK: - Async/Await API (iOS 15+)
    
    // Basic GET request
    func fetchUsers() async throws -> [User] {
        guard let url = URL(string: "https://api.example.com/users") else {
            throw URLError(.badURL)
        }
        
        var request = URLRequest(url: url)
        request.setValue("application/json", forHTTPHeaderField: "Accept")
        request.setValue("Bearer your-token", forHTTPHeaderField: "Authorization")
        
        let (data, response) = try await session.data(for: request)
        
        guard let httpResponse = response as? HTTPURLResponse else {
            throw URLError(.badServerResponse)
        }
        
        guard httpResponse.statusCode == 200 else {
            throw URLError(.init(rawValue: httpResponse.statusCode))
        }
        
        let users = try JSONDecoder().decode([User].self, from: data)
        return users
    }
    
    // GET request with query parameters
    func fetchUsersWithParams(page: Int, limit: Int) async throws -> [User] {
        var components = URLComponents(string: "https://api.example.com/users")!
        components.queryItems = [
            URLQueryItem(name: "page", value: String(page)),
            URLQueryItem(name: "limit", value: String(limit)),
            URLQueryItem(name: "sort", value: "created_at")
        ]
        
        guard let url = components.url else {
            throw URLError(.badURL)
        }
        
        let (data, response) = try await session.data(from: url)
        
        if let httpResponse = response as? HTTPURLResponse {
            print("Response status: \(httpResponse.statusCode)")
            print("Response headers: \(httpResponse.allHeaderFields)")
        }
        
        return try JSONDecoder().decode([User].self, from: data)
    }
    
    // POST request (sending JSON)
    func createUser(_ user: User) async throws -> User {
        guard let url = URL(string: "https://api.example.com/users") else {
            throw URLError(.badURL)
        }
        
        var request = URLRequest(url: url)
        request.httpMethod = "POST"
        request.setValue("application/json", forHTTPHeaderField: "Content-Type")
        request.setValue("application/json", forHTTPHeaderField: "Accept")
        request.setValue("Bearer your-token", forHTTPHeaderField: "Authorization")
        
        // JSON encode request body
        let encoder = JSONEncoder()
        encoder.dateEncodingStrategy = .iso8601
        request.httpBody = try encoder.encode(user)
        
        let (data, response) = try await session.data(for: request)
        
        guard let httpResponse = response as? HTTPURLResponse else {
            throw URLError(.badServerResponse)
        }
        
        if httpResponse.statusCode == 201 {
            let createdUser = try JSONDecoder().decode(User.self, from: data)
            print("User created: \(createdUser.name)")
            return createdUser
        } else {
            // Handle error response
            let errorResponse = try JSONDecoder().decode(ErrorResponse.self, from: data)
            throw NSError(domain: "APIError", code: errorResponse.code, userInfo: [
                NSLocalizedDescriptionKey: errorResponse.error
            ])
        }
    }
    
    // PUT request (data update)
    func updateUser(id: Int, updates: [String: Any]) async throws -> User {
        guard let url = URL(string: "https://api.example.com/users/\(id)") else {
            throw URLError(.badURL)
        }
        
        var request = URLRequest(url: url)
        request.httpMethod = "PUT"
        request.setValue("application/json", forHTTPHeaderField: "Content-Type")
        request.setValue("Bearer your-token", forHTTPHeaderField: "Authorization")
        
        // Convert Dictionary directly to JSON
        request.httpBody = try JSONSerialization.data(withJSONObject: updates)
        
        let (data, response) = try await session.data(for: request)
        
        guard let httpResponse = response as? HTTPURLResponse,
              httpResponse.statusCode == 200 else {
            throw URLError(.badServerResponse)
        }
        
        return try JSONDecoder().decode(User.self, from: data)
    }
    
    // DELETE request
    func deleteUser(id: Int) async throws {
        guard let url = URL(string: "https://api.example.com/users/\(id)") else {
            throw URLError(.badURL)
        }
        
        var request = URLRequest(url: url)
        request.httpMethod = "DELETE"
        request.setValue("Bearer your-token", forHTTPHeaderField: "Authorization")
        
        let (_, response) = try await session.data(for: request)
        
        guard let httpResponse = response as? HTTPURLResponse,
              httpResponse.statusCode == 204 else {
            throw URLError(.badServerResponse)
        }
        
        print("User deletion completed")
    }
}

// MARK: - Traditional Callback-based API (iOS 13+)

extension NetworkManager {
    
    // Callback-based request for legacy support
    func fetchUsersLegacy(completion: @escaping (Result<[User], Error>) -> Void) {
        guard let url = URL(string: "https://api.example.com/users") else {
            completion(.failure(URLError(.badURL)))
            return
        }
        
        var request = URLRequest(url: url)
        request.setValue("application/json", forHTTPHeaderField: "Accept")
        
        let task = session.dataTask(with: request) { data, response, error in
            if let error = error {
                completion(.failure(error))
                return
            }
            
            guard let data = data,
                  let httpResponse = response as? HTTPURLResponse,
                  httpResponse.statusCode == 200 else {
                completion(.failure(URLError(.badServerResponse)))
                return
            }
            
            do {
                let users = try JSONDecoder().decode([User].self, from: data)
                completion(.success(users))
            } catch {
                completion(.failure(error))
            }
        }
        
        task.resume()
    }
}

Advanced Configuration and Customization (Authentication, Timeout, Cache, etc.)

import Foundation
import Network

class AdvancedNetworkManager {
    
    // MARK: - Custom URLSessionConfiguration
    
    static func createCustomSession() -> URLSession {
        let config = URLSessionConfiguration.default
        
        // Timeout settings
        config.timeoutIntervalForRequest = 30.0
        config.timeoutIntervalForResource = 120.0
        
        // Connectivity settings
        config.waitsForConnectivity = true
        config.allowsCellularAccess = true
        config.allowsExpensiveNetworkAccess = true
        config.allowsConstrainedNetworkAccess = false
        
        // Cache configuration
        let cache = URLCache(
            memoryCapacity: 50 * 1024 * 1024,    // 50MB
            diskCapacity: 200 * 1024 * 1024,     // 200MB
            diskPath: "networking_cache"
        )
        config.urlCache = cache
        config.requestCachePolicy = .reloadIgnoringLocalCacheData
        
        // Header configuration
        config.httpAdditionalHeaders = [
            "User-Agent": "MyApp/1.0 (iOS)",
            "Accept-Language": "en-US,ja-JP",
            "X-API-Version": "v2"
        ]
        
        // HTTP configuration
        config.httpMaximumConnectionsPerHost = 6
        config.httpShouldUsePipelining = true
        config.httpShouldSetCookies = true
        config.httpCookieAcceptPolicy = .always
        
        return URLSession(configuration: config)
    }
    
    // MARK: - Background Download Configuration
    
    static func createBackgroundSession() -> URLSession {
        let config = URLSessionConfiguration.background(
            withIdentifier: "com.myapp.background-download"
        )
        
        // Background-specific settings
        config.isDiscretionary = true  // Enable system optimization
        config.sessionSendsLaunchEvents = true
        
        // Connection settings
        config.waitsForConnectivity = true
        config.allowsCellularAccess = false  // WiFi only
        
        return URLSession(configuration: config, delegate: nil, delegateQueue: nil)
    }
    
    // MARK: - Authentication Features
    
    class AuthenticationManager: NSObject, URLSessionDelegate {
        
        // HTTP Basic Authentication
        func urlSession(
            _ session: URLSession,
            task: URLSessionTask,
            didReceive challenge: URLAuthenticationChallenge,
            completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void
        ) {
            
            let authenticationMethod = challenge.protectionSpace.authenticationMethod
            
            switch authenticationMethod {
            case NSURLAuthenticationMethodHTTPBasic:
                let credential = URLCredential(
                    user: "username",
                    password: "password",
                    persistence: .forSession
                )
                completionHandler(.useCredential, credential)
                
            case NSURLAuthenticationMethodServerTrust:
                // SSL Certificate Pinning
                handleServerTrust(challenge: challenge, completionHandler: completionHandler)
                
            default:
                completionHandler(.performDefaultHandling, nil)
            }
        }
        
        private func handleServerTrust(
            challenge: URLAuthenticationChallenge,
            completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void
        ) {
            
            guard let serverTrust = challenge.protectionSpace.serverTrust else {
                completionHandler(.performDefaultHandling, nil)
                return
            }
            
            // Custom validation for certificate pinning
            let policy = SecPolicyCreateSSL(true, "api.example.com" as CFString)
            SecTrustSetPolicies(serverTrust, policy)
            
            var secResult = SecTrustResultType.invalid
            let status = SecTrustEvaluate(serverTrust, &secResult)
            
            if status == errSecSuccess &&
               (secResult == .unspecified || secResult == .proceed) {
                let credential = URLCredential(trust: serverTrust)
                completionHandler(.useCredential, credential)
            } else {
                completionHandler(.cancelAuthenticationChallenge, nil)
            }
        }
    }
    
    // MARK: - Custom HTTP Header Management
    
    func createAuthenticatedRequest(url: URL, token: String) -> URLRequest {
        var request = URLRequest(url: url)
        
        // Authentication headers
        request.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
        
        // Custom headers
        request.setValue("application/json", forHTTPHeaderField: "Accept")
        request.setValue("application/json", forHTTPHeaderField: "Content-Type")
        request.setValue(UUID().uuidString, forHTTPHeaderField: "X-Request-ID")
        request.setValue("MyApp/1.0", forHTTPHeaderField: "User-Agent")
        
        // Cache control
        request.cachePolicy = .reloadIgnoringLocalAndRemoteCacheData
        
        return request
    }
    
    // MARK: - Proxy Configuration (iOS 14+)
    
    @available(iOS 14.0, *)
    func configureProxySettings() -> URLSessionConfiguration {
        let config = URLSessionConfiguration.default
        
        // HTTP proxy settings
        let proxySettings: [String: Any] = [
            kCFNetworkProxiesHTTPEnable as String: true,
            kCFNetworkProxiesHTTPProxy as String: "proxy.example.com",
            kCFNetworkProxiesHTTPPort as String: 8080,
            kCFNetworkProxiesHTTPSEnable as String: true,
            kCFNetworkProxiesHTTPSProxy as String: "proxy.example.com",
            kCFNetworkProxiesHTTPSPort as String: 8080
        ]
        
        config.connectionProxyDictionary = proxySettings
        
        return config
    }
}

Error Handling and Retry Functionality

import Foundation
import os.log

// Custom error definitions
enum NetworkError: LocalizedError {
    case invalidURL
    case noData
    case decodingError(Error)
    case serverError(Int, String?)
    case networkUnavailable
    case timeout
    case unauthorized
    case rateLimited(retryAfter: TimeInterval?)
    
    var errorDescription: String? {
        switch self {
        case .invalidURL:
            return "Invalid URL"
        case .noData:
            return "No data received"
        case .decodingError(let error):
            return "Data parsing failed: \(error.localizedDescription)"
        case .serverError(let code, let message):
            return "Server error (\(code)): \(message ?? "Unknown error")"
        case .networkUnavailable:
            return "Network unavailable"
        case .timeout:
            return "Request timed out"
        case .unauthorized:
            return "Authentication required"
        case .rateLimited(let retryAfter):
            let after = retryAfter.map { String(format: "%.0f seconds", $0) } ?? "a while"
            return "Rate limited. Please retry after \(after)"
        }
    }
}

class RobustNetworkManager {
    private let session: URLSession
    private let logger = Logger(subsystem: "com.myapp.networking", category: "api")
    
    init() {
        let config = URLSessionConfiguration.default
        config.timeoutIntervalForRequest = 30
        config.waitsForConnectivity = true
        self.session = URLSession(configuration: config)
    }
    
    // MARK: - Request with Retry Functionality
    
    func fetchWithRetry<T: Codable>(
        url: URL,
        type: T.Type,
        maxRetries: Int = 3,
        backoffMultiplier: Double = 2.0
    ) async throws -> T {
        
        var lastError: Error?
        
        for attempt in 0...maxRetries {
            do {
                logger.info("API request attempt \(attempt + 1)/\(maxRetries + 1): \(url)")
                
                let (data, response) = try await session.data(from: url)
                
                guard let httpResponse = response as? HTTPURLResponse else {
                    throw NetworkError.serverError(0, "Invalid response")
                }
                
                // Status code handling
                switch httpResponse.statusCode {
                case 200...299:
                    logger.info("API request successful: \(httpResponse.statusCode)")
                    return try JSONDecoder().decode(type, from: data)
                    
                case 401:
                    throw NetworkError.unauthorized
                    
                case 429:
                    let retryAfter = httpResponse.value(forHTTPHeaderField: "Retry-After")
                        .flatMap { Double($0) }
                    throw NetworkError.rateLimited(retryAfter: retryAfter)
                    
                case 500...599:
                    if attempt < maxRetries {
                        let delay = pow(backoffMultiplier, Double(attempt))
                        logger.warning("Server error \(httpResponse.statusCode), retrying in \(delay)s")
                        try await Task.sleep(nanoseconds: UInt64(delay * 1_000_000_000))
                        continue
                    }
                    throw NetworkError.serverError(httpResponse.statusCode, nil)
                    
                default:
                    throw NetworkError.serverError(httpResponse.statusCode, nil)
                }
                
            } catch let error as NetworkError {
                lastError = error
                
                // Non-retryable errors
                if case .unauthorized = error, case .rateLimited = error {
                    throw error
                }
                
                if attempt < maxRetries {
                    let delay = pow(backoffMultiplier, Double(attempt))
                    logger.warning("Request failed: \(error), retrying in \(delay)s")
                    try await Task.sleep(nanoseconds: UInt64(delay * 1_000_000_000))
                }
                
            } catch {
                lastError = error
                
                // Retry on network errors
                if (error as NSError).domain == NSURLErrorDomain {
                    if attempt < maxRetries {
                        let delay = pow(backoffMultiplier, Double(attempt))
                        logger.warning("Network error: \(error), retrying in \(delay)s")
                        try await Task.sleep(nanoseconds: UInt64(delay * 1_000_000_000))
                        continue
                    }
                }
                
                throw error
            }
        }
        
        throw lastError ?? NetworkError.networkUnavailable
    }
    
    // MARK: - Comprehensive Error Handling
    
    func handleResponse<T: Codable>(
        data: Data,
        response: URLResponse,
        type: T.Type
    ) throws -> T {
        
        guard let httpResponse = response as? HTTPURLResponse else {
            throw NetworkError.serverError(0, "Not an HTTP response")
        }
        
        logger.info("Response: \(httpResponse.statusCode) \(HTTPURLResponse.localizedString(forStatusCode: httpResponse.statusCode))")
        
        switch httpResponse.statusCode {
        case 200...299:
            do {
                return try JSONDecoder().decode(type, from: data)
            } catch {
                logger.error("JSON decoding failed: \(error)")
                throw NetworkError.decodingError(error)
            }
            
        case 400:
            if let errorData = try? JSONDecoder().decode(ErrorResponse.self, from: data) {
                throw NetworkError.serverError(400, errorData.error)
            }
            throw NetworkError.serverError(400, "Bad Request")
            
        case 401:
            throw NetworkError.unauthorized
            
        case 404:
            throw NetworkError.serverError(404, "Resource not found")
            
        case 429:
            let retryAfter = httpResponse.value(forHTTPHeaderField: "Retry-After")
                .flatMap { Double($0) }
            throw NetworkError.rateLimited(retryAfter: retryAfter)
            
        case 500...599:
            throw NetworkError.serverError(httpResponse.statusCode, "Internal server error")
            
        default:
            throw NetworkError.serverError(httpResponse.statusCode, "Unexpected error")
        }
    }
    
    // MARK: - Network Connectivity Monitoring
    
    @available(iOS 12.0, *)
    func checkNetworkConnectivity() async -> Bool {
        let monitor = NWPathMonitor()
        let queue = DispatchQueue(label: "network_monitor")
        
        return await withCheckedContinuation { continuation in
            monitor.pathUpdateHandler = { path in
                let isConnected = path.status == .satisfied
                monitor.cancel()
                continuation.resume(returning: isConnected)
            }
            monitor.start(queue: queue)
        }
    }
}

// Usage example
@MainActor
class ViewModel: ObservableObject {
    @Published var users: [User] = []
    @Published var isLoading = false
    @Published var errorMessage: String?
    
    private let networkManager = RobustNetworkManager()
    
    func loadUsers() async {
        isLoading = true
        errorMessage = nil
        
        do {
            guard let url = URL(string: "https://api.example.com/users") else {
                throw NetworkError.invalidURL
            }
            
            users = try await networkManager.fetchWithRetry(
                url: url,
                type: [User].self,
                maxRetries: 3
            )
            
        } catch let error as NetworkError {
            errorMessage = error.localizedDescription
        } catch {
            errorMessage = "Unexpected error: \(error.localizedDescription)"
        }
        
        isLoading = false
    }
}

File Operations and Upload/Download

import Foundation

class FileTransferManager {
    private let session: URLSession
    
    init() {
        let config = URLSessionConfiguration.default
        config.timeoutIntervalForResource = 600 // 10 minutes
        self.session = URLSession(configuration: config)
    }
    
    // MARK: - File Download
    
    func downloadFile(from url: URL, to destinationURL: URL) async throws {
        let (tempURL, response) = try await session.download(from: url)
        
        guard let httpResponse = response as? HTTPURLResponse,
              httpResponse.statusCode == 200 else {
            throw URLError(.badServerResponse)
        }
        
        // Move temporary file to destination
        try FileManager.default.moveItem(at: tempURL, to: destinationURL)
        
        print("File download completed: \(destinationURL.path)")
    }
    
    // Download with progress (using URLSessionDownloadDelegate)
    func downloadWithProgress(from url: URL) -> AsyncThrowingStream<DownloadProgress, Error> {
        return AsyncThrowingStream { continuation in
            let task = session.downloadTask(with: url) { tempURL, response, error in
                if let error = error {
                    continuation.finish(throwing: error)
                    return
                }
                
                guard let tempURL = tempURL,
                      let httpResponse = response as? HTTPURLResponse,
                      httpResponse.statusCode == 200 else {
                    continuation.finish(throwing: URLError(.badServerResponse))
                    return
                }
                
                // Final progress
                continuation.yield(DownloadProgress(
                    bytesWritten: httpResponse.expectedContentLength,
                    totalBytes: httpResponse.expectedContentLength,
                    progress: 1.0,
                    tempURL: tempURL
                ))
                
                continuation.finish()
            }
            
            task.resume()
        }
    }
    
    // MARK: - File Upload
    
    func uploadFile(fileURL: URL, to uploadURL: URL) async throws -> UploadResponse {
        var request = URLRequest(url: uploadURL)
        request.httpMethod = "POST"
        request.setValue("application/octet-stream", forHTTPHeaderField: "Content-Type")
        request.setValue("Bearer your-token", forHTTPHeaderField: "Authorization")
        
        let (data, response) = try await session.upload(for: request, fromFile: fileURL)
        
        guard let httpResponse = response as? HTTPURLResponse,
              httpResponse.statusCode == 200 || httpResponse.statusCode == 201 else {
            throw URLError(.badServerResponse)
        }
        
        return try JSONDecoder().decode(UploadResponse.self, from: data)
    }
    
    // Multipart form data upload
    func uploadMultipartForm(
        fileURL: URL,
        fields: [String: String],
        to uploadURL: URL
    ) async throws -> UploadResponse {
        
        let boundary = UUID().uuidString
        var request = URLRequest(url: uploadURL)
        request.httpMethod = "POST"
        request.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
        request.setValue("Bearer your-token", forHTTPHeaderField: "Authorization")
        
        let multipartData = createMultipartData(
            fileURL: fileURL,
            fields: fields,
            boundary: boundary
        )
        
        let (data, response) = try await session.upload(for: request, from: multipartData)
        
        guard let httpResponse = response as? HTTPURLResponse,
              httpResponse.statusCode == 200 || httpResponse.statusCode == 201 else {
            throw URLError(.badServerResponse)
        }
        
        return try JSONDecoder().decode(UploadResponse.self, from: data)
    }
    
    private func createMultipartData(
        fileURL: URL,
        fields: [String: String],
        boundary: String
    ) -> Data {
        var data = Data()
        
        // Add field data
        for (key, value) in fields {
            data.append("--\(boundary)\r\n".data(using: .utf8)!)
            data.append("Content-Disposition: form-data; name=\"\(key)\"\r\n\r\n".data(using: .utf8)!)
            data.append("\(value)\r\n".data(using: .utf8)!)
        }
        
        // Add file data
        let filename = fileURL.lastPathComponent
        let mimeType = mimeTypeForFile(url: fileURL)
        
        data.append("--\(boundary)\r\n".data(using: .utf8)!)
        data.append("Content-Disposition: form-data; name=\"file\"; filename=\"\(filename)\"\r\n".data(using: .utf8)!)
        data.append("Content-Type: \(mimeType)\r\n\r\n".data(using: .utf8)!)
        
        if let fileData = try? Data(contentsOf: fileURL) {
            data.append(fileData)
        }
        
        data.append("\r\n--\(boundary)--\r\n".data(using: .utf8)!)
        
        return data
    }
    
    private func mimeTypeForFile(url: URL) -> String {
        let pathExtension = url.pathExtension.lowercased()
        
        switch pathExtension {
        case "jpg", "jpeg":
            return "image/jpeg"
        case "png":
            return "image/png"
        case "pdf":
            return "application/pdf"
        case "txt":
            return "text/plain"
        case "json":
            return "application/json"
        default:
            return "application/octet-stream"
        }
    }
    
    // MARK: - Background Download
    
    func backgroundDownload(from url: URL) -> URLSessionDownloadTask {
        let backgroundConfig = URLSessionConfiguration.background(
            withIdentifier: "com.myapp.background-download"
        )
        let backgroundSession = URLSession(configuration: backgroundConfig)
        
        let task = backgroundSession.downloadTask(with: url)
        task.resume()
        
        return task
    }
}

// Related type definitions
struct DownloadProgress {
    let bytesWritten: Int64
    let totalBytes: Int64
    let progress: Double
    let tempURL: URL?
}

struct UploadResponse: Codable {
    let fileId: String
    let filename: String
    let size: Int64
    let url: String
}

// SwiftUI usage example
struct FileDownloadView: View {
    @State private var downloadProgress: Double = 0
    @State private var isDownloading = false
    
    private let fileManager = FileTransferManager()
    
    var body: some View {
        VStack {
            if isDownloading {
                ProgressView(value: downloadProgress, total: 1.0)
                    .progressViewStyle(LinearProgressViewStyle())
                Text("Downloading: \(Int(downloadProgress * 100))%")
            } else {
                Button("Download File") {
                    Task {
                        await startDownload()
                    }
                }
            }
        }
    }
    
    private func startDownload() async {
        isDownloading = true
        
        guard let url = URL(string: "https://api.example.com/files/large-file.zip") else {
            return
        }
        
        do {
            let documentsPath = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
            let destinationURL = documentsPath.appendingPathComponent("downloaded-file.zip")
            
            try await fileManager.downloadFile(from: url, to: destinationURL)
            
        } catch {
            print("Download error: \(error)")
        }
        
        isDownloading = false
    }
}

Combine Framework Integration and Practical Usage Examples

import Foundation
import Combine
import SwiftUI

// MARK: - Combine Publisher Extensions

extension URLSession {
    
    // Generic API request Publisher
    func apiRequest<T: Codable>(
        for request: URLRequest,
        responseType: T.Type
    ) -> AnyPublisher<T, NetworkError> {
        
        return dataTaskPublisher(for: request)
            .tryMap { data, response -> T in
                guard let httpResponse = response as? HTTPURLResponse else {
                    throw NetworkError.serverError(0, "Invalid response")
                }
                
                guard 200...299 ~= httpResponse.statusCode else {
                    throw NetworkError.serverError(httpResponse.statusCode, nil)
                }
                
                do {
                    return try JSONDecoder().decode(T.self, from: data)
                } catch {
                    throw NetworkError.decodingError(error)
                }
            }
            .mapError { error in
                if let networkError = error as? NetworkError {
                    return networkError
                } else {
                    return NetworkError.networkUnavailable
                }
            }
            .receive(on: DispatchQueue.main)
            .eraseToAnyPublisher()
    }
}

// MARK: - Combine-based API Client

class CombineAPIClient: ObservableObject {
    private let session = URLSession.shared
    private var cancellables = Set<AnyCancellable>()
    
    @Published var users: [User] = []
    @Published var isLoading = false
    @Published var errorMessage: String?
    
    // Fetch user list
    func fetchUsers() {
        guard let url = URL(string: "https://api.example.com/users") else {
            errorMessage = "Invalid URL"
            return
        }
        
        var request = URLRequest(url: url)
        request.setValue("application/json", forHTTPHeaderField: "Accept")
        
        isLoading = true
        errorMessage = nil
        
        session.apiRequest(for: request, responseType: [User].self)
            .sink(
                receiveCompletion: { [weak self] completion in
                    self?.isLoading = false
                    
                    if case .failure(let error) = completion {
                        self?.errorMessage = error.localizedDescription
                    }
                },
                receiveValue: { [weak self] users in
                    self?.users = users
                }
            )
            .store(in: &cancellables)
    }
    
    // Reactive user search
    func searchUsers(query: String) -> AnyPublisher<[User], NetworkError> {
        guard !query.isEmpty,
              let url = URL(string: "https://api.example.com/users/search") else {
            return Just([])
                .setFailureType(to: NetworkError.self)
                .eraseToAnyPublisher()
        }
        
        var request = URLRequest(url: url)
        request.httpMethod = "POST"
        request.setValue("application/json", forHTTPHeaderField: "Content-Type")
        
        let searchData = ["query": query]
        request.httpBody = try? JSONSerialization.data(withJSONObject: searchData)
        
        return session.apiRequest(for: request, responseType: [User].self)
            .debounce(for: .milliseconds(300), scheduler: DispatchQueue.main)
            .removeDuplicates { $0.count == $1.count }
            .eraseToAnyPublisher()
    }
    
    // Batch request processing
    func fetchUserDetails(ids: [Int]) {
        let publishers = ids.map { id in
            fetchUserDetail(id: id)
                .catch { _ in Just(nil) }
        }
        
        Publishers.MergeMany(publishers)
            .collect()
            .sink { userDetails in
                let validUsers = userDetails.compactMap { $0 }
                print("Fetched user details: \(validUsers.count) items")
            }
            .store(in: &cancellables)
    }
    
    private func fetchUserDetail(id: Int) -> AnyPublisher<User?, Never> {
        guard let url = URL(string: "https://api.example.com/users/\(id)") else {
            return Just(nil).eraseToAnyPublisher()
        }
        
        let request = URLRequest(url: url)
        
        return session.apiRequest(for: request, responseType: User.self)
            .map { Optional($0) }
            .replaceError(with: nil)
            .eraseToAnyPublisher()
    }
}

// MARK: - SwiftUI Integration

struct UserListView: View {
    @StateObject private var apiClient = CombineAPIClient()
    @State private var searchText = ""
    @State private var searchResults: [User] = []
    
    var body: some View {
        NavigationView {
            VStack {
                // Search bar
                SearchBar(text: $searchText)
                    .onChange(of: searchText) { query in
                        searchUsers(query: query)
                    }
                
                // User list
                if apiClient.isLoading {
                    ProgressView("Loading...")
                } else if !searchResults.isEmpty {
                    List(searchResults, id: \.id) { user in
                        UserRowView(user: user)
                    }
                } else {
                    List(apiClient.users, id: \.id) { user in
                        UserRowView(user: user)
                    }
                }
                
                Spacer()
            }
            .navigationTitle("User List")
            .onAppear {
                apiClient.fetchUsers()
            }
            .alert("Error", isPresented: .constant(apiClient.errorMessage != nil)) {
                Button("OK") {
                    apiClient.errorMessage = nil
                }
            } message: {
                Text(apiClient.errorMessage ?? "")
            }
        }
    }
    
    private func searchUsers(query: String) {
        apiClient.searchUsers(query: query)
            .receive(on: DispatchQueue.main)
            .sink(
                receiveCompletion: { _ in },
                receiveValue: { users in
                    searchResults = users
                }
            )
            .store(in: &apiClient.cancellables)
    }
}

struct UserRowView: View {
    let user: User
    
    var body: some View {
        HStack {
            VStack(alignment: .leading) {
                Text(user.name)
                    .font(.headline)
                Text(user.email)
                    .font(.caption)
                    .foregroundColor(.secondary)
            }
            
            Spacer()
            
            if let age = user.age {
                Text("\(age) years old")
                    .font(.caption)
                    .foregroundColor(.secondary)
            }
        }
        .padding(.vertical, 4)
    }
}

struct SearchBar: View {
    @Binding var text: String
    
    var body: some View {
        HStack {
            Image(systemName: "magnifyingglass")
                .foregroundColor(.secondary)
            
            TextField("Search users...", text: $text)
                .textFieldStyle(RoundedBorderTextFieldStyle())
        }
        .padding(.horizontal)
    }
}

// MARK: - WebSocket Communication Example

@available(iOS 13.0, *)
class WebSocketManager: NSObject, ObservableObject {
    @Published var connectionStatus: WebSocketConnectionStatus = .disconnected
    @Published var receivedMessages: [String] = []
    
    private var webSocketTask: URLSessionWebSocketTask?
    private let session = URLSession(configuration: .default)
    
    func connect(to url: URL) {
        webSocketTask = session.webSocketTask(with: url)
        webSocketTask?.resume()
        
        connectionStatus = .connecting
        
        // Start receiving messages
        receiveMessage()
        
        // Monitor connection status
        DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
            self.connectionStatus = .connected
        }
    }
    
    func sendMessage(_ text: String) {
        let message = URLSessionWebSocketTask.Message.string(text)
        webSocketTask?.send(message) { error in
            if let error = error {
                print("WebSocket send error: \(error)")
            }
        }
    }
    
    func disconnect() {
        webSocketTask?.cancel(with: .normalClosure, reason: nil)
        connectionStatus = .disconnected
    }
    
    private func receiveMessage() {
        webSocketTask?.receive { [weak self] result in
            switch result {
            case .success(let message):
                switch message {
                case .string(let text):
                    DispatchQueue.main.async {
                        self?.receivedMessages.append(text)
                    }
                case .data(let data):
                    print("Received data: \(data)")
                @unknown default:
                    break
                }
                
                // Receive next message
                self?.receiveMessage()
                
            case .failure(let error):
                print("WebSocket receive error: \(error)")
                DispatchQueue.main.async {
                    self?.connectionStatus = .disconnected
                }
            }
        }
    }
}

enum WebSocketConnectionStatus {
    case disconnected
    case connecting
    case connected
}