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 | |
| API Key | Uses a key for API access | |
| Basic Auth | Uses username/password | |
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 expectedNSURLErrorCannotFindHost– Hostname could not be resolvedNSURLErrorNetworkConnectionLost– Connection was lost during transferNSURLErrorNotConnectedToInternet– 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+ |