본문 바로가기

Swift

데이터 모델 이름을 바꿔야 한다면?

JSON 응답의 구조와 코드에 있는 구조체의 불일치를 해결하기 위해서는 구조체 이름을 유지하면서, 일부 이름을 수정하고 적절한 타입 매핑을 수행해야 합니다.

 

 

실제 외부 API를 통해 받아온 데이터 모델 

{
  "response": {
    "header": {
      "resultCode": "0000",
      "resultMsg": "OK"
    },
    "body": {
      "items": {
        "item": [
          {
            "contentid": "1095732",
            "originimgurl": "http://tong.visitkorea.or.kr/cms/resource/67/3035567_image2_1.png",
            "imgname": "서울빛초롱축제 포스터",
            "smallimageurl": "http://tong.visitkorea.or.kr/cms/resource/67/3035567_image3_1.png",
            "cpyrhtDivCd": "Type3",
            "serialnum": "3035567_3"
          },
          {
            "contentid": "1095732",
            "originimgurl": "http://tong.visitkorea.or.kr/cms/resource/68/3035568_image2_1.jpg",
            "imgname": "서울빛초롱축제 1",
            "smallimageurl": "http://tong.visitkorea.or.kr/cms/resource/68/3035568_image3_1.jpg",
            "cpyrhtDivCd": "Type3",
            "serialnum": "3035568_2"
          },
          ...
        ]
      },
      "numOfRows": 10,
      "pageNo": 1,
      "totalCount": 11
    }
  }
}

 

 

⭐️ 위에 나온 대로 데이터 모델을 작성하면 되지만, 이거 말고 다른 데이터 모델을 사용하고 있으면서 이전의 이름이 공통으로 사용되는 부분이 있어서 이름을 좀 바꿔야 했습니다. 

 

 

수정된 데이터 모델

import Foundation

// 최상위 응답 구조체
struct ImageResponseResponse: Codable {
    let response: ImageResponse
}

// 응답의 상위 구조체
struct ImageResponse: Codable {
    let header: ImageHeader
    let body: ImageBody
}

// 헤더 정보
struct ImageHeader: Codable {
    let resultCode: String
    let resultMsg: String
}

// 바디 구조체 (실제 데이터가 포함되는 부분)
struct ImageBody: Codable {
    let items: ImageItems
    let numOfRows: Int
    let pageNo: Int
    let totalCount: Int
}

// 아이템들을 포함하는 구조체
struct ImageItems: Codable {
    let item: [ImageItem]
}

// 각각의 이미지 정보를 포함하는 구조체
struct ImageItem: Codable {
    let contentid: String
    let originimgurl: String
    let imgname: String
    let smallimageurl: String
    let cpyrhtDivCd: String
    let serialnum: String
}

// CodingKeys를 사용하여 JSON의 키와 프로퍼티를 매핑
extension ImageResponseResponse {
    enum CodingKeys: String, CodingKey {
        case response
    }
}

extension ImageResponse {
    enum CodingKeys: String, CodingKey {
        case header
        case body
    }
}

extension ImageHeader {
    enum CodingKeys: String, CodingKey {
        case resultCode
        case resultMsg
    }
}

extension ImageBody {
    enum CodingKeys: String, CodingKey {
        case items
        case numOfRows
        case pageNo
        case totalCount
    }
}

extension ImageItems {
    enum CodingKeys: String, CodingKey {
        case item
    }
}

 

 

⭐️ ImageItem 구조체에 대해 CodingKeys를 따로 정의할 필요는 없습니다. 이유는 ImageItem에 포함된 프로퍼티 이름들이 JSON의 키 이름과 정확히 일치하기 때문입니다. Swift의 Codable 프로토콜은 기본적으로 프로퍼티 이름과 JSON 키가 동일한 경우 자동으로 매핑을 해줍니다.

 

 

🔥 CodingKeys가 필요한 경우 🔥

CodingKeys는 JSON의 키와 구조체의 프로퍼티 이름이 다를 때 사용됩니다. 예를 들어, 만약 JSON에서 contentid라는 키가 content_id로 되어 있으면, CodingKeys를 사용하여 다음과 같이 매핑할 수 있습니다.

struct ImageItem: Codable {
    let contentid: String
    let originimgurl: String
    let imgname: String
    let smallimageurl: String
    let cpyrhtDivCd: String
    let serialnum: String

    enum CodingKeys: String, CodingKey {
        case contentid = "content_id"
        case originimgurl = "origin_image_url"
        case imgname = "image_name"
        case smallimageurl = "small_image_url"
        case cpyrhtDivCd = "copyright_code"
        case serialnum = "serial_number"
    }
}

 

 

1. CodingKeys를 구조체 내부에 정의하는 방법

가장 흔히 사용되는 방식으로, 구조체 내부에 CodingKeys를 정의하는 것입니다. 이 방식은 CodingKeys가 구조체의 일부임을 명확하게 보여줍니다. 

struct ImageItem: Codable {
    let contentid: String
    let originimgurl: String
    let imgname: String
    let smallimageurl: String
    let cpyrhtDivCd: String
    let serialnum: String

    enum CodingKeys: String, CodingKey {
        case contentid
        case originimgurl
        case imgname
        case smallimageurl
        case cpyrhtDivCd
        case serialnum
    }
}

 

2. extension을 사용해서 CodingKeys를 정의하는 방법

당신이 보낸 것처럼 extension을 사용하면, 구조체 본체와 CodingKeys 정의를 분리할 수 있습니다. 이는 코드의 가독성을 높이거나, 확장성 있는 구조로 관리하려고 할 때 유용할 수 있습니다.

struct ImageItem: Codable {
    let contentid: String
    let originimgurl: String
    let imgname: String
    let smallimageurl: String
    let cpyrhtDivCd: String
    let serialnum: String
}

extension ImageItem {
    enum CodingKeys: String, CodingKey {
        case contentid
        case originimgurl
        case imgname
        case smallimageurl
        case cpyrhtDivCd
        case serialnum
    }
}

 

 

두 방법의 차이

  1. 구조적 차이:
    • extension을 사용하면 구조체 자체와 CodingKeys 정의를 분리해서 관리할 수 있어, 특히 복잡한 구조체나 여러 가지 확장 기능이 있을 때 도움이 됩니다.
    • 구조체 내부에 정의하면 모든 관련 코드가 한 곳에 있어서, 한눈에 구조체의 설계와 CodingKeys가 어떻게 매핑되는지 파악할 수 있습니다.
  2. 유연성:
    • extension을 사용하면 나중에 구조체를 확장하거나, 추가적인 기능을 모듈화하고 분리된 파일에 정의하는 것이 더 쉽습니다.
  3. 스타일:
    • 둘 중 어느 방식이 더 좋은지는 팀의 코드 스타일에 따라 다릅니다. 일반적으로 작은 구조체에서는 내부에 CodingKeys를 정의하고, 코드가 길어지거나 관리해야 할 것이 많을 때는 extension을 사용하기도 합니다.

결론

  • 기능적인 차이는 없습니다. 둘 다 CodingKeys를 제공하는 방식일 뿐입니다.
  • extension은 구조를 분리해서 좀 더 모듈화된 코드를 만들 수 있게 해줍니다.