Skip to main content

Working with Networking

1. Using URLSession for Requests

Property Description Example
URLSession Class for managing URL requests and responses URLSession.shared
URLRequest Represents a URL request with method, headers, and body URLRequest(url: url)
URLSessionDataTask Task for downloading data from a URL session.dataTask(with: request)

Example: Making a GET Request

let url = URL(string: "https://api.example.com/data")!
let task = URLSession.shared.dataTask(with: url) { data, response, error in
    if let error = error {
        print("Error: \(error)")
        return
    }
    
    if let data = data {
        print("Received data: \(data)")
    }
}
task.resume()

Example: Making a POST Request

let url = URL(string: "https://api.example.com/submit")!
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.httpBody = "{\"name\": \"John\"}".data(using: .utf8)
request.setValue("application/json", forHTTPHeaderField: "Content-Type")

let task = URLSession.shared.dataTask(with: request) { data, response, error in
    if let error = error {
        print("Error: \(error)")
        return
    }
    
    if let data = data {
        print("Response: \(data)")
    }
}
task.resume()
Note: Always handle errors and optional data safely to prevent runtime crashes.

2. Creating URLRequest

Property Value Description
url URL? The URL to request
httpMethod String? HTTP method (GET, POST, etc.)
httpBody Data? Request body data
allHTTPHeaderFields [String: String]? Custom HTTP headers

Example: Creating a URLRequest

let url = URL(string: "https://api.example.com/data")!
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.httpBody = "{\"name\": \"John\"}".data(using: .utf8)
request.setValue("application/json", forHTTPHeaderField: "Content-Type")

3. Making GET Requests

Method Description Notes
URLSession.shared.dataTask(with:) Creates a data task to retrieve data from a URL Most commonly used for GET requests
URLSessionDataTask Represents a task that retrieves data from a URL Can be used to send GET requests with optional parameters

Example: Basic GET Request

import Foundation

let url = URL(string: "https://jsonplaceholder.typicode.com/posts/1")!
let task = URLSession.shared.dataTask(with: url) { data, response, error in
    if let error = error {
        print("Error: \(error)")
        return
    }
    
    if let data = data {
        do {
            let json = try JSONSerialization.jsonObject(with: data) as? [String: Any]
            print(json ?? "No data")
        } catch {
            print("JSON parsing error: \(error)")
        }
    }
}

task.resume()

Example: GET Request with Codable

import Foundation

struct Post: Codable {
    let id: Int
    let title: String
    let body: String
    let userId: Int
}

let url = URL(string: "https://jsonplaceholder.typicode.com/posts/1")!
let task = URLSession.shared.dataTask(with: url) { data, response, error in
    if let error = error {
        print("Error: \(error)")
        return
    }
    
    guard let data = data else {
        print("No data received")
        return
    }
    
    do {
        let post = try JSONDecoder().decode(Post.self, from: data)
        print("Title: \(post.title)")
    } catch {
        print("Decoding error: \(error)")
    }
}

task.resume()

4. Making POST Requests

Method Description Notes
URLSession.dataTask(with:) Initiates a POST request with data payload Requires setting HTTPMethod to "POST"
URLSession.uploadTask(with:from:) Uploads data to a server Useful for file uploads or large payloads

Example: Basic POST Request

import Foundation

let url = URL(string: "https://api.example.com/users")!
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")

let parameters = ["name": "John Doe", "email": "john@example.com"]
let jsonData = try! JSONSerialization.data(withJSONObject: parameters)
request.httpBody = jsonData

let task = URLSession.shared.dataTask(with: request) { data, response, error in
    if let error = error {
        print("Error: \(error)")
        return
    }
    
    if let httpResponse = response as? HTTPURLResponse {
        print("Status Code: \(httpResponse.statusCode)")
    }
    
    if let data = data {
        print("Response Data: \(String(data: data, encoding: .utf8) ?? \"\")")
    }
}

task.resume()
Note: Always handle errors and validate the response status code in production code.
Warning: Ensure sensitive data is sent over HTTPS to prevent interception.

5. Handling Response Data

Property Description Usage
data The raw data received from the server Used to parse JSON, XML, or other formats
statusCode HTTP status code returned by the server Used to determine success or failure of request
headers HTTP headers returned by the server Used to extract metadata like content type or authentication tokens

Example: Parsing JSON Response

guard let json = try? JSONSerialization.jsonObject(with: data) else {
    print("Failed to parse JSON")
    return
}
print(json)

Example: Handling HTTP Status Code

if statusCode == 200 {
    print("Request successful")
} else if statusCode == 404 {
    print("Resource not found")
} else {
    print("Unexpected status code: \(statusCode)")
}

Example: Reading Response Headers

if let contentType = headers["Content-Type"] {
    print("Content-Type: \(contentType)")
}

6. Parsing JSON with Codable

Property Type Description
CodingKey Protocol Defines the keys used to encode and decode values.
Encodable Protocol Defines types that can be encoded into a data format like JSON.
Decodable Protocol Defines types that can be decoded from a data format like JSON.
Codable Alias Convenience alias for Encodable & Decodable.

Example: Basic Codable Implementation

struct User: Codable {
    let id: Int
    let name: String
    let email: String
}

Example: JSON Parsing with Codable

let jsonData = """
{
    "id": 1,
    "name": "John Doe",
    "email": "john@example.com"
}
""".data(using: .utf8)!

do {
    let user = try JSONDecoder().decode(User.self, from: jsonData)
    print("User: \(user.name)")
} catch {
    print("Failed to decode JSON: \(error)")
}

Example: Handling Optional Fields

struct OptionalUser: Codable {
    let id: Int
    let name: String
    let email: String?
}
Note: When using JSONDecoder, ensure that the keys in your JSON match the property names in your Codable struct. You can customize key mapping using CodingKey or keyDecodingStrategy.
Warning: If a JSON field is missing or invalid, JSONDecoder will throw an error. Always wrap decoding in a do-catch block.

7. Using URLSessionDataTask

Property Description Example
url The URL to be requested URL(string: "https://api.example.com/data")
httpMethod HTTP method to use (GET, POST, etc.) "GET"
httpBody Data to send in the body of a POST request data
timeoutInterval Maximum time to wait for a response 30.0

Example: Fetching Data with URLSessionDataTask

let url = URL(string: "https://api.example.com/data")!
let task = URLSession.shared.dataTask(with: url) { data, response, error in
    if let error = error {
        print("Error: \(error)")
        return
    }
    
    if let data = data {
        print("Received \(data.count) bytes")
    }
}
task.resume()
Note: The resume() method must be called to start the task.
Warning: Always handle errors and check for valid data in the completion handler.

8. Using URLSessionDownloadTask

Property Value Description
url URL The URL to download from
destinationURL URL The local file URL where the downloaded data will be saved
downloadTask URLSessionDownloadTask The task instance used to manage the download

Example: Downloading a file using URLSessionDownloadTask

import Foundation

let url = URL(string: "https://example.com/file.zip")!
let session = URLSession.shared

let downloadTask = session.downloadTask(with: url) { localURL, response, error in
    if let error = error {
        print("Download failed: \(error)")
        return
    }

    guard let localURL = localURL else {
        print("No local URL")
        return
    }

    print("Downloaded file to: \(localURL)")
}

downloadTask.resume()
Note: The downloadTask must be resumed to start the download process.

Key Points

  • URLSessionDownloadTask is used for downloading files asynchronously.
  • The completion handler provides the local file URL, response, and any error.
  • Always call resume() to initiate the download.

9. Using URLSessionUploadTask

Property Description Values
url The URL to upload data to URL
httpMethod HTTP method to use (e.g., POST) String
httpBody Data to upload Data
httpBodyStream Stream of data to upload InputStream

Example: Uploading Data with URLSessionUploadTask

let url = URL(string: "https://api.example.com/upload")!
let request = NSMutableURLRequest(url: url)
request.httpMethod = "POST"
request.httpBody = "Hello, World!".data(using: .utf8)!

let task = URLSession.shared.uploadTask(with: request as URLRequest, from: request.httpBody!) { data, response, error in
    if let error = error {
        print("Upload failed: \(error)")
    } else {
        print("Upload successful")
    }
}
task.resume()
Note: URLSessionUploadTask is ideal for uploading data to a server. It supports both direct data and stream-based uploads.

10. Implementing Request Authentication

Authentication Type Description Implementation
Bearer Token Uses a token for API access
let token = "your-token-here"
var request = URLRequest(url: URL(string: "https://api.example.com/data")!)
request.httpMethod = "GET"
request.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
API Key Uses a key for API access
let apiKey = "your-api-key"
var request = URLRequest(url: URL(string: "https://api.example.com/data")!)
request.httpMethod = "GET"
request.setValue(apiKey, forHTTPHeaderField: "X-API-Key")
Basic Auth Uses username/password
let user = "username"
let password = "password"
let credentials = "\(user):\(password)"
let credentialData = credentials.data(using: .utf8)!
let base64Credentials = credentialData.base64EncodedString()
var request = URLRequest(url: URL(string: "https://api.example.com/data")!)
request.httpMethod = "GET"
request.setValue("Basic \(base64Credentials)", forHTTPHeaderField: "Authorization")

Example: Using Bearer Token Authentication

import Foundation

func fetchWithBearerToken() {
    guard let url = URL(string: "https://api.example.com/data") else { return }
    
    var request = URLRequest(url: url)
    request.httpMethod = "GET"
    request.setValue("Bearer your-token-here", forHTTPHeaderField: "Authorization")
    
    let task = URLSession.shared.dataTask(with: request) { data, response, error in
        if let error = error {
            print("Error: \(error)")
            return
        }
        
        if let data = data {
            print("Response: \(data)")
        }
    }
    
    task.resume()
}

11. Handling Network Errors

Error Type Description Handling Strategy
URLSessionTaskError Errors related to task execution like timeouts or invalid URLs Check error.code and handle accordingly using URLSessionTaskError cases
HTTPStatusCodeError Non-2xx HTTP status codes returned by the server Inspect response.statusCode and implement custom logic for each status code (e.g., 404, 500)
NetworkUnavailableError Device has no network connectivity Display user-friendly message and retry logic when connection is restored

Example: Basic Error Handling in URLSession

let url = URL(string: "https://api.example.com/data")!
let task = URLSession.shared.dataTask(with: url) { data, response, error in
    if let error = error {
        print("Network Error: \(error.localizedDescription)")
        return
    }
    
    guard let httpResponse = response as? HTTPURLResponse else {
        print("Invalid response")
        return
    }
    
    switch httpResponse.statusCode {
    case 200...299:
        // Success
        print("Data received successfully")
    case 400...499:
        print("Client error: \(httpResponse.statusCode)")
    case 500...599:
        print("Server error: \(httpResponse.statusCode)")
    default:
        print("Unexpected status code: \(httpResponse.statusCode)")
    }
}
task.resume()
Note: Always handle error in completion handlers to prevent unhandled exceptions and provide meaningful feedback to users.

Common Network Error Codes

  • NSURLErrorTimedOut – Request took longer than expected
  • NSURLErrorCannotFindHost – Hostname could not be resolved
  • NSURLErrorNetworkConnectionLost – Connection was lost during transfer
  • NSURLErrorNotConnectedToInternet – No active internet connection

12. Monitoring Network Reachability

Property Value Description
NetworkReachability NetworkReachability Class for monitoring network reachability status
status NetworkReachability.Status Current network status (online, offline, unknown)
isOnline Bool Boolean indicating if device is online

Example: Check Network Reachability

import Network

let monitor = NWPathMonitor()
let queue = DispatchQueue(label: "NetworkMonitor")

monitor.start(queue: queue) { path in
    if path.status == .satisfied {
        print("Network is reachable")
    } else {
        print("No network connection")
    }
}
Note: The Network framework is available from iOS 12.0+
Warning: NWPathMonitor does not provide real-time updates for cellular networks. Use NetworkReachabilityManager from Alamofire or similar libraries for more accurate monitoring.
Status Description Support
satisfied Network is available and reachable iOS 12+
unsatisfied No network connection iOS 12+
transient Network is temporarily unavailable iOS 12+

Was this article helpful?