JSON Processing in Swift (iOS/macOS): From Basics to Advanced Usage
JSON (JavaScript Object Notation) is one of the most popular data exchange formats in mobile and desktop development. In the Swift ecosystem (iOS/macOS), working with JSON is implemented natively and elegantly, starting with the Codable protocol (Swift 4+) and ending with the low-level JSONSerialization from Foundation. In this article, we will break down all the key approaches, show code examples, and provide practical recommendations for the educational website pythonlib.ru.
1. Basics: The Codable Protocol
The Codable protocol is a combination of Encodable and Decodable. It automatically generates code to convert your structures and classes to and from JSON. This is the primary and recommended way to work with JSON in modern Swift.
1.1. Simple Data Model
import Foundation
struct User: Codable { let id: Int let name: String let email: String let isActive: Bool}
// Example JSON stringlet jsonString = """{ "id": 1, "name": "Ivan Petrov", "email": "ivan@example.com", "isActive": true}"""
// Decodingif let jsonData = jsonString.data(using: .utf8) { let decoder = JSONDecoder() if let user = try? decoder.decode(User.self, from: jsonData) { print("User: \\(user.name), email: \\(user.email)") }}1.2. Custom Keys (CodingKeys)
If the keys in JSON differ from your model's properties (e.g., snake_case in JSON, camelCase in Swift), use the CodingKeys enum:
struct Product: Codable { let productId: Int let productName: String let price: Double
enum CodingKeys: String, CodingKey { case productId = "product_id" case productName = "product_name" case price }}
let jsonProduct = """{ "product_id": 101, "product_name": "MacBook Pro", "price": 2499.99}"""2. Working with Arrays and Nested Objects
JSON often contains arrays of objects or nested structures. Codable handles this effortlessly:
struct Author: Codable { let name: String let books: [Book]}
struct Book: Codable { let title: String let year: Int}
let jsonLibrary = """{ "name": "Joan Rowling", "books": [ {"title": "Harry Potter and the Philosopher's Stone", "year": 1997}, {"title": "Harry Potter and the Chamber of Secrets", "year": 1998} ]}"""
if let data = jsonLibrary.data(using: .utf8) { let author = try? JSONDecoder().decode(Author.self, from: data) print("Author: \\(author?.name ?? ""), books: \\(author?.books.count ?? 0)")}3. JSONSerialization — Low-Level Approach
Although Codable is the preferred method, sometimes you need to work with dynamic or unstructured data. In such cases, use JSONSerialization from Foundation:
let jsonString = """{ "status": "success", "data": { "temperature": 22.5, "humidity": 65, "city": "Moscow" }}"""
if let data = jsonString.data(using: .utf8) { do { if let json = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] { if let status = json["status"] as? String { print("Status: \\(status)") } if let dataDict = json["data"] as? [String: Any], let temp = dataDict["temperature"] as? Double { print("Temperature: \\(temp)°C") } } } catch { print("JSON parsing error: \\(error.localizedDescription)") }}4. Error Handling and Optional Values
Real JSON data