iOS/Swift

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

밤새는 탐험가89 2024. 9. 6. 02:31

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은 구조를 분리해서 좀 더 모듈화된 코드를 만들 수 있게 해줍니다.