ios swift处理json数据

1. 使用 Codable 协议(推荐)

基本使用

swift

复制代码
// 定义模型
struct User: Codable {
    let id: Int
    let name: String
    let email: String?
    let age: Int?
    
    // 如果键名不同,使用 CodingKeys
    private enum CodingKeys: String, CodingKey {
        case id, name, email, age
    }
}

// 解析 JSON
let jsonString = """
{
    "id": 1,
    "name": "John",
    "email": "john@example.com",
    "age": 30
}
"""

do {
    let jsonData = Data(jsonString.utf8)
    let user = try JSONDecoder().decode(User.self, from: jsonData)
    print(user.name)  // 输出: John
} catch {
    print("解码错误: \(error)")
}

// 编码为 JSON
let user = User(id: 1, name: "Jane", email: nil, age: 25)
do {
    let jsonData = try JSONEncoder().encode(user)
    let jsonString = String(data: jsonData, encoding: .utf8)
} catch {
    print("编码错误: \(error)")
}

处理嵌套 JSON

swift

复制代码
struct Post: Codable {
    let title: String
    let author: User
    let tags: [String]
}

// 自定义日期格式
struct Event: Codable {
    let name: String
    let date: Date
}

let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .iso8601
// 或自定义格式
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
decoder.dateDecodingStrategy = .formatted(formatter)

2. 使用 JSONSerialization

swift

复制代码
// 解析 JSON
let jsonString = """
{
    "name": "Swift",
    "version": 5.0
}
"""

if let data = jsonString.data(using: .utf8) {
    do {
        if let json = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] {
            let name = json["name"] as? String
            let version = json["version"] as? Double
            print("Name: \(name ?? ""), Version: \(version ?? 0)")
        }
    } catch {
        print("JSON 解析错误: \(error)")
    }
}

// 创建 JSON
let dict: [String: Any] = [
    "name": "iOS",
    "version": 15.0,
    "features": ["SwiftUI", "ARKit"]
]

do {
    let jsonData = try JSONSerialization.data(withJSONObject: dict, options: .prettyPrinted)
    if let jsonString = String(data: jsonData, encoding: .utf8) {
        print(jsonString)
    }
} catch {
    print("JSON 创建错误: \(error)")
}

3. 处理复杂场景

自定义解码

swift

复制代码
struct Product: Codable {
    let id: Int
    let name: String
    let price: Double
    let discountPrice: Double?
    
    // 自定义解码逻辑
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        id = try container.decode(Int.self, forKey: .id)
        name = try container.decode(String.self, forKey: .name)
        price = try container.decode(Double.self, forKey: .price)
        
        // 处理可选值
        discountPrice = try container.decodeIfPresent(Double.self, forKey: .discountPrice)
        
        // 数据验证
        if price < 0 {
            throw DecodingError.dataCorruptedError(
                forKey: .price,
                in: container,
                debugDescription: "价格不能为负数"
            )
        }
    }
}

使用 Property Wrapper

swift

复制代码
@propertyWrapper
struct DefaultEmptyString: Codable {
    var wrappedValue: String
    
    init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        wrappedValue = (try? container.decode(String.self)) ?? ""
    }
}

struct Profile: Codable {
    @DefaultEmptyString var nickname: String
    @DefaultEmptyString var bio: String
}

4. 网络请求中的 JSON 处理

swift

复制代码
import Foundation

struct NetworkService {
    func fetchData<T: Decodable>(from url: URL) async throws -> T {
        let (data, response) = try await URLSession.shared.data(from: url)
        
        guard let httpResponse = response as? HTTPURLResponse,
              (200...299).contains(httpResponse.statusCode) else {
            throw URLError(.badServerResponse)
        }
        
        let decoder = JSONDecoder()
        decoder.keyDecodingStrategy = .convertFromSnakeCase  // 处理蛇形命名
        
        return try decoder.decode(T.self, from: data)
    }
}

// 使用示例
struct APIResponse<T: Codable>: Codable {
    let status: Int
    let message: String
    let data: T
}

// 调用
Task {
    do {
        let url = URL(string: "https://api.example.com/users")!
        let response: APIResponse<[User]> = try await NetworkService().fetchData(from: url)
        print(response.data)
    } catch {
        print("错误: \(error)")
    }
}

5. 使用第三方库

Swift Package Manager 添加依赖

swift

复制代码
// 在 Package.swift 中添加
dependencies: [
    .package(url: "https://github.com/SwiftyJSON/SwiftyJSON.git", from: "5.0.0")
]

SwiftyJSON 示例

swift

复制代码
import SwiftyJSON

let json = JSON(parseJSON: jsonString)
let name = json["user"]["name"].stringValue
let age = json["user"]["age"].intValue

// 安全访问
if let email = json["user"]["email"].string {
    print(email)
}

6. 最佳实践

  1. 始终使用 do-catch 处理错误

  2. 使用可选类型处理可能缺失的数据

  3. 为 API 响应创建专门的模型

  4. 使用 keyDecodingStrategy 处理命名约定

  5. 考虑使用 Result 类型

swift

复制代码
enum NetworkError: Error {
    case invalidURL
    case noData
    case decodingError
}

func parseJSON<T: Decodable>(data: Data) -> Result<T, NetworkError> {
    do {
        let decodedData = try JSONDecoder().decode(T.self, from: data)
        return .success(decodedData)
    } catch {
        return .failure(.decodingError)
    }
}

7. 性能优化技巧

swift

复制代码
// 重用 JSONDecoder/JSONEncoder
class JSONManager {
    static let shared: JSONDecoder = {
        let decoder = JSONDecoder()
        decoder.dateDecodingStrategy = .iso8601
        decoder.keyDecodingStrategy = .convertFromSnakeCase
        return decoder
    }()
}

// 使用 lazy 延迟解码
struct LazyDecoded<T: Decodable>: Decodable {
    let value: T
    init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        self.value = try container.decode(T.self)
    }
}

这些方法涵盖了 Swift 中处理 JSON 的主要场景。Codable 是现代 Swift 开发中最推荐的方式,因为它类型安全、代码简洁。

相关推荐
数研小生4 小时前
构建命令行单词记忆工具:JSON 词库与艾宾浩斯复习算法的完美结合
算法·json
编码者卢布10 小时前
【Azure Stream Analytic】用 JavaScript UDF 解决 JSON 字段被转成 Record 的关键点
javascript·json·azure
2501_9159214311 小时前
傻瓜式 HTTPS 抓包,简单抓取iOS设备数据
android·网络协议·ios·小程序·https·uni-app·iphone
电商API&Tina13 小时前
电商数据采集 API 接口 全维度解析(技术 + 商业 + 合规)
java·大数据·开发语言·数据库·人工智能·json
liwulin050613 小时前
【JSON】使用com.fasterxml.jackson解析json字符串
java·数据库·json
恋猫de小郭13 小时前
Flutter 在 Android 出现随机字体裁剪?其实是图层合并时的边界计算问题
android·flutter·ios
2501_9159184114 小时前
把 iOS 性能监控融入日常开发与测试流程的做法
android·ios·小程序·https·uni-app·iphone·webview
Digitally16 小时前
如何轻松地将大型音频文件从 iPhone 发送到不同的设备
ios·iphone
catchadmin17 小时前
PHP 现在可以零成本构建原生 iOS 和 Android 应用 NativePHP for Mobile v3 发布
android·ios·php
奔跑的呱呱牛18 小时前
geojson-to-kml (KML 格式转换工具)
arcgis·json