[회고] 신입 iOS 개발자가 되기까지 feat. 카카오 자세히보기

🍎 Apple/Swift

[Swift] CodingKeys / Custom CodingKeys

inu 2022. 5. 12. 23:10
반응형

CodingKeys

CodingKeys

struct Model: Codable {
    var name: String
    var number: Int
}
// JSON File
{
    "myName" : "Inu",
    "number" : 5
}
  • 우리는 주로 Codable Protocol을 채택하여 모델을 구성합니다.
  • 이 때 구현하려는 구조체의 속성과 JSON Data의 Key값이 일치해야 정상적으로 Decoding됩니다.
  • 그런데 사실 구현하려는 구조체의 속성과 JSON Data의 Key값이 일치하는 경우는 거의 없습니다.
  • 위의 예시의 name과 myName처럼 다른 것이 일반적입니다.
  • 이 때 사용되는 것이 CodingKeys 입니다.
struct Model: Codable {
    var name: String
    var number: Int

    enum CodingKeys: String, CodingKey {
        case name = "myName"
        case number
    }
}
  • mapping될 속성을 CodingKeys 열거형에 추가합니다.
  • CodingKeys 열거형은 CodingKey Protocol을 채용해야 합니다.
  • mapping이 달라지는 속성의 rawValue로 필요한 JSON Data의 Key값을 입력합니다.

Custom Encoding, Decoding

  • 인코딩 혹은 디코딩 시점에 값을 검증하거나 제약을 주고 싶을 경우 사용합니다.
  • 기본으로 제공되는 인코딩 및 디코딩 객체에 제공되는 속성이나 CodingKeys로는 원하는 결과를 만들 수 없다면 이를 활용해야 합니다.
struct Model: Codable {
    var name: String
    var number: Int
    var realName: String?

    func encode(to encoder: Encoder) throws {
        var container = encoder.contatiner(keyedBy: CodingKeys.self)
        try container.encode(name, forKey: .name)

        guard (0...10).contains(number) else { throw EncodingError.invalidRange }
        try container.encode(number, forKey: .number)
        try container.encodeIfPresent(realName, forKey: .realName)
    }
}
  • encoding 처리된 데이터는 encoder 내부에 컨테이너 형태로 저장되기 때문에 먼저 해당 container를 가져옵니다.
  • 이는 CodingKey 열거형에 존재하는 Key값과 속성을 매핑할 수 있는 container입니다.
  • container.encode를 통해 내부 속성을 Key값과 매핑시켜 저장합니다.
  • guard 문을 통해 범위를 확인하고 범위에 해당하지 않을 경우 에러를 방출할 수 있습니다. (EncodingError.invalidRange는 직접 선언한 Error 입니다.)
  • optional 값의 경우 encodeIfPresent를 사용합니다.
struct Model: Codable {
    var name: String
    var number: Int
    var realName: String?

    init(from decoder: Decoder) throws {
        let container = decoder.contatiner(keyedBy: CodingKeys.self)

        name = try container.decode(String.self, forKey: .name)
        number = try container.decode(Int.self, forKey: .number)
        guard (0...10).contains(number) else { throw EncodingError.invalidRange }

           realName = try container.decodeIfPresent(String.self, forKey: .realName)
    }
}
  • encoder와 마찬가지로 container를 가져옵니다.
  • container.decode를 통해 원하는 key의 값을 원하는 타입으로 받아올 수 있습니다.
  • guard 문을 통해 범위를 확인하고 범위에 해당하지 않을 경우 에러를 방출할 수 있습니다. (EncodingError.invalidRange는 직접 선언한 Error 입니다.)
  • optional 값의 경우 decodeIfPresent를 사용합니다.
반응형

'🍎 Apple > Swift' 카테고리의 다른 글

[Swift] URLSession Cahce Policy  (1) 2022.05.18
[Swift] URL Loading System  (0) 2022.05.12
[Swift] JSON Encoding / Decoding  (0) 2022.05.12
[Swift] ATS (App Transport Security)  (0) 2022.05.12
[Swift] 순열과 조합 구현  (2) 2022.04.25