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 开发中最推荐的方式,因为它类型安全、代码简洁。

相关推荐
黑码哥2 小时前
iOS开屏广告多机型屏幕适配最佳实践
macos·ios·cocoa·广告·商业·开屏广告
Swift社区2 小时前
LeetCode 473 火柴拼正方形 - Swift 题解
算法·leetcode·swift
前端不太难3 小时前
Flutter / RN / iOS,在长期维护下谁更容易“止损”?
flutter·ios·状态模式
CareyWYR12 小时前
我开发了一款工具箱类型APP:CreativeUtil
ios·app·mac
2501_9159184114 小时前
只有 Flutter IPA 文件,通过多工具组合完成有效混淆与保护
android·flutter·ios·小程序·uni-app·iphone·webview
Wpa.wk18 小时前
性能测试工具 - JMeter工具组件介绍二
运维·经验分享·测试工具·jmeter·自动化·json
川石课堂软件测试20 小时前
Android和iOS APP平台测试的区别
android·数据库·ios·oracle·单元测试·测试用例·cocoa
liusheng20 小时前
Capacitor + React 的 iOS 侧滑返回手势
前端·ios
大熊猫侯佩21 小时前
Swift 6.2 列传(第十七篇):钟灵的“雷电蟒”与测试附件
单元测试·swift·apple