[Swift] Json Codable, Decodable 정리

1. 기본값 설정

서버에서 온 값이 nil 이 들어오면 보통 옵셔널로 설정합니다. 하지만 매번 사용할때 옵셔널에서 일반 타입으로 변경하는게 귀찮을 때 다음과 같이 init 함수에서 기본값을 설정해주면 옵셔널이 없는 일반 struct 처럼 사용 가능합니다.

struct param: Codable {
    var key: String
    var value: String

    private enum CodingKeys: String, CodingKey {
        case key, value
    }

    init(from decoder: Decoder) throws {
        let values = try decoder.container(keyedBy: CodingKeys.self)
        key = (try? values.decode(String.self, forKey: .key)) ?? ""
        value = (try? values.decode(String.self, forKey: .value)) ?? ""
    }
}

 

2. 코딩키 설정

서버에서 온 JSON의 키 값을 변경할 때 사용가능합니다. 예를 들어 "__id" 와 같은 키값을 id 로 선언할 수 있습니다.

struct param: Codable {
    var id : Int
    var key: String
    var value: String

    private enum CodingKeys: String, CodingKey {
        case id = "__id"
        case key
        case value = "real_value"
    }
}

 

3. 스네이크 케이스(snake case) 무시하기

코딩키 설정을 하면 키 값을 자신이 원하는 값으로 변경할 수 있습니다. 하지만 번거롭기도 하죠. 때문에 서버에서 온값이 스네이크 케이스(snake case) 로 모두 동일하다면 이를 카멜 케이스 (camel case)로 변경 가능합니다.

let decoder = JSONDecoder()
decoder.keyDecodingStratege = .convertFromSnakeCase

 

4. NSDate 객체 변환

서버에서 온 값중에 Date 형태의 JSON을 스위프트의 Date 객체로 손쉽게 변환하는 방법이 있습니다. 

let json = 
"""
{
    "name": "myName",
    "birth": "1992-11-11T11:1700Z"
}
"""

struct Person: Codable {
    name: String
    birth: Date
}

let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .iso8601

 

5. 동적 타입 설정

만약 서버에서 오는 값이 nil 이라면 옵셔널을 선언해서 사용하면 되지만, 내려오는 값이 매번 달라진다면 문제가 됩니다. 어떤때는 String, 어떤 때는 Int로 말이죠. 이때는 커스텀 타입을 만들어줘서 해결합니다.

enum MyValue: Codable {
    case string(String)
    case double(Double)

    init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        if let x = try? container.decode(String.self) {
            self = .string(x)
            return
        }
        if let x = try? container.decode(Double.self) {
            self = .double(x)
            return
        }
        throw DecodingError.typeMismatch(MyValue.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Wrong type for MyValue"))
    }

    func encode(to encoder: Encoder) throws {
        var container = encoder.singleValueContainer()
        switch self {
        case .string(let x):
            try container.encode(x)
        case .double(let x):
            try container.encode(x)
        }
    }
}

enum 타입을 이용해서 다음과 같이 선언해주면 됩니다. 해당 타입은 enum 이기 때문에 실제 사용할 때 switch 문을 이용해서 사용해야 합니다.

struct rcgList: Codable {
    var mvnoName: String?
    var sortNo: String?
    var amounts: String?
    var mvnoId: MyValue?
    var rcgType: String?
}

댓글

Designed by JB FACTORY