swift Codable

unkeyedContainersingleValueContainer

struct Student: Codable {
    let name: String
    init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        name = try container.decode(String.self)
    }
}

struct Classes: Codable {
    let students: [Student]
    
    init(from decoder: Decoder) throws {
        var container = try decoder.unkeyedContainer()
        students = try (0..

解析:

let decode = JSONDecoder()
let stuData = #"""
     [
         "张三",
         "李四"
     ]
"""#.data(using: .utf8)!

do {
    let student = try decode.decode(Classes.self, from: stuData)
    print(student)
    // Classes(students: [__lldb_expr_27.Student(name: "张三"), __lldb_expr_27.Student(name: "李四")])
} catch let err {
    print(err)
}

decodeIfPresent(_:, forKey:)decode(_:, forKey:)

struct Student: Codable {
    let sex: Int?
    let name: String
    let age: Int

    enum Keys: String, CodingKey {
        case name = "first_name"
    }
    
    init(from decoder: Decoder) throws {
        let container0 = try decoder.container(keyedBy: CodingKeys.self)
        sex = try container0.decodeIfPresent(Int.self, forKey: .sex)
        age = try container0.decode(Int.self, forKey: .age)
        
        let container = try decoder.container(keyedBy: Keys.self)
        name = try container.decode(String.self, forKey: .name)
    }
}

JSON:

let stuData = #"""
    {
        "first_name": "张三",
        "age": 45,
        "class": 3
    }
"""#.data(using: .utf8)!
// Student(sex: nil, name: "张三", age: 45)

nestedUnkeyedContainer
协议:

protocol Student: Codable {
    var sex: Int? { get }
    var name: String { get }
    var age: Int { get }
}

enum StudentKeys: String, CodingKey {
    case name = "first_name"
}

struct Pupil: Student {
    let sex: Int?
    let name: String
    let age: Int
    let `class`: String
    
    init(from decoder: Decoder) throws {
        let container0 = try decoder.container(keyedBy: CodingKeys.self)
        sex = try container0.decodeIfPresent(Int.self, forKey: .sex)
        age = try container0.decode(Int.self, forKey: .age)
        `class` = "\(try container0.decode(Int.self, forKey: .class))班"
        
        let container = try decoder.container(keyedBy: StudentKeys.self)
        name = try container.decode(String.self, forKey: .name)
    }
}

struct College: Student {
    let sex: Int?
    let name: String
    let age: Int
    let year: String
    
    init(from decoder: Decoder) throws {
        let container0 = try decoder.container(keyedBy: CodingKeys.self)
        sex = try container0.decodeIfPresent(Int.self, forKey: .sex)
        age = try container0.decode(Int.self, forKey: .age)
        year = try container0.decode(String.self, forKey: .year)
        
        let container = try decoder.container(keyedBy: StudentKeys.self)
        name = try container.decode(String.self, forKey: .name)
    }
}

struct Classes: Codable {
    let students: [Student]
    
    enum CodingKeys: String, CodingKey {
        case students
    }
    
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        var arrContainer = try container.nestedUnkeyedContainer(forKey: .students)
        let college = try arrContainer.decode(College.self)
        let pupil = try arrContainer.decode(Pupil.self)
        
        students = [college, pupil]
    }
    
    func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        var arrContainer = container.nestedUnkeyedContainer(forKey: .students)
        
        for student in students {
            if let college = student as? College {
                try arrContainer.encode(college)
            } else if let pupil = student as? Pupil {
                try arrContainer.encode(pupil)
            }
        }
    }
}

JSON:

{
    "students":[
        {
            "first_name": "张三",
            "age": 45,
            "year": "2201级"
        },
        {
            "first_name": "李四",
            "age": 45,
            "class": 3
        }
    ]
}

Classes(students: [__lldb_expr_78.College(sex: nil, name: "张三", age: 45, year: "2201级"), __lldb_expr_78.Pupil(sex: nil, name: "李四", age: 45, class: "3班")])

nestedContainer(keyedBy:)

struct Student: Codable {
    let name: String
    
    init(from decoder: Decoder) throws {
        var container = try decoder.unkeyedContainer()
        let container0 = try container.nestedContainer(keyedBy: CodingKeys.self)
        let container1 = try container.nestedContainer(keyedBy: CodingKeys.self)
                
        name = try container0.decode(String.self, forKey: .name) + "_" + (try container1.decode(String.self, forKey: .name))
    }
}
[
  {"name": "张三"},
  {"name": "李四"}
]

Student(name: "张三_李四")

你可能感兴趣的:(swift Codable)