본문 바로가기
iOS/Swift

Swift) Codable, Decode, Encode

by Jiseong 2022. 2. 13.

Codable

아 Hashable도 공부해보고싶은데 담에 해봐야지

 

Codable에 대해 알아보자

정의는 좀 의역을 섞어보면 자신을 변환하거나 외부 표현을 변환할 수 있는 타입이란다.

 

아 아직 의역안했는데 저서 외부표현이란 JSON 같은 것들이라고 생각하면 된다.

 

아 그래도 의역안한거네

 

왜 JSON 같은 것들이라 했느냐 하면 요기를 보면 

이래서 했다

 

다시 본론으로 가보면.. 

 

Codable은 Decodable & Encodable 을 묶어서 표현한 것이다.

Encode

먼저 Encodable에 대해 알아보자

 

Encodable을 채택한 타입은 자신(타입)이 JSON으로 파싱될 수 있음을 표현한다.

 

예제를 보자

struct Cafe: Codable {
    var kind: String
    var menu: String
}

우선 Cafe 타입이 Codable 프로토콜을 채택함으로써 Cafe 타입은 JSON으로 변환될 수도 있고, JSON이 나(Cafe)로 변환될 수 있음을 알렸다.

 

저거 채택안해주면 디코딩 인코딩 못한다. 

 

인코드, 디코드 메소드가 있는데 내부로 들어가서 파라미터를 보면 제네릭으로 타입 제한(조건)(Encodable or Decodable)이 걸려있음을 볼 수 있다.

이래도 볼 수 있네요 

어 근데 저 위에 플레이스홀더 아직 안써준 코드처럼 써주면 컴파일 오류가 발생한다.

 

왜냐하면 encode 메소드는 오류를 던질 수 있다고(throw) 명시되어 있다.

 

encoding 중 오류가 발생할 수 있으므로 try와 함께 써줘야한다. 에러처리는 다루지 않을 거다. 그냥 try? 로 할거임

let encoder = JSONEncoder()
let JSCafe = Cafe(name: "JSCafe", rent: 100000000)

let cafeData = try? encoder.encode(JSCafe)

if let cafeData = cafeData, let cafeStringData = String(data: cafeData, encoding: .utf8) {
    print(cafeStringData)
}

try?를 써서 반환값이 옵셔널인데, 출력을 위해 옵셔널 바인딩을 해주었다. 

 

그리고 string으로 변환해주었는데, 왜 해줬을까?

 

encode 메소드의 반환타입은 Data 타입임을 위의 사진에서 알 수 있고, 그러니 우리가 원하는 JSON을 보려면 String으로 변환을 해줘야 한다.

 

안해주면..

이꼴남

 

첨에 저거 몰라서 한 5분 헤맸다.. 인코딩 했는데 왜 JSON 처럼 안나와!!!!! 했는데 String으로 변환해줘야되더라 ㅎㅎ;;

아 Data를 변환해주는 메소드가 따로 있어서 써주면 된다.

 

물론 얘도 반환타입 보면 옵셔널 타입이니 바인딩 해줘야 됨

 

그러면~ 출력이 어떻게 되느냐

?

내가 원하는 JSON 모양이 아니다.. 

 

API 쓸 때 받아오는 JSON은 이 모양이 아니거든.. 

 

그럴 땐 밑의 코드를 사용해주면 된다.

"to make output easy to read" ㅎㅎ 굿

됐당

Decode

그럼 Decodable은 뭘까? De..De..를 생각해보자

 

De.. 하니깐 해제가 먼저 생각난다. 비슷하다.

 

JSON을 다른 타입(여기선 자신)으로 해제(해석?,변환)한다는 의미이다

.

Encoder랑 똑같다. 순서만 반대인거지

 

이전 코드 그대로 활용해보겠다.

let dataString = """
{
  "name" : "JSCafe",
  "rent" : 100000000
}
"""

다음은 인코더와 동일하게 Decoder 인스턴스를 생성해주고, 위의 dataString을 Data 타입으로 변환해줘야 한다. 그래야 decode 메소드를 사용할 수 있다.

얘도 동일하게 제네릭으로 타입 제한 걸려있고(Decodable 채택한 타입만), 오류를 던질 수 있게 되어있다.

let decoder = JSONDecoder()

let data = dataString.data(using: .utf8)

if let data = data, let JSCafe = try? decoder.decode(Cafe.self, from: data) {
    print(JSCafe.name) // JSCafe
    print(JSCafe.rent) // 10000000
}

decode 메소드가 사용되며 data가 우리가 지정한 인스턴스로 변환된 것이다.

Change Key Names

위 코드 예제들은 JSON의 키 이름과, 우리가 지정한 클래스 프로퍼티의 이름이 같았다.

 

근데 만약 다르면 어떡해야될까? 

 

JSON을 Decoding하는데 키가 다르면 데이터는 당연히 아무것도 변환이 되지 않을 것이다.

이렇게.. 아무것도 출력이 안된다.

 

변환 자체가 안됐기때문에 출력이고 자시고 할게 없어서 우리가 만든 JSON의 키 이름은 바꿀 수야 있다쳐도 외부에서 받아오는 API의 JSON은 키를 못바꾼다.

 

그렇다고 그 API 키에 맞춰서 내 프로퍼티 명을 바꾸자니 그건 또 말도 안된다.

 

그럴 때 해결 방법이 있다.

해당 프로토콜을 JSON 변환될 클래스의 내부 열거형에 채택해주고, JSON의 키와 클래스 프로퍼티를 맵핑(연결)하면 된다.

바로 예제로 들어가보겠다.

struct Cafe: Codable {
    var name123: String
    var rent123: Int
    
    private enum CodingKeys: String, CodingKey {
        case name123 = "name"
        case rent123 = "rent"
    }
}

let dataString = """
{
  "name" : "JSCafe",
  "rent" : 100000000
}
"""

JSON의 키인 "name", "rent"와 클래스 프로퍼티명이 다르다.

 

그때 CodingKey 프로토콜을 활용하여 프로퍼티를 케이스로 정의한 열거형(private enum CodingKeys)의 각 케이스에 맞는 JSON의 키값을 넣어주면 맵핑이 된다.

정상적으로 연결되어 변환이 됨을 확인 할 수 있다.

'iOS > Swift' 카테고리의 다른 글

Swift) Dynamic Type, Accessibility Inspector  (0) 2022.02.13
Swift) 문자열의 특정 범위의 속성을 변경해보자 NSMutableAttributedString  (0) 2022.02.13
Swift) TableView  (0) 2022.02.13
Swift) Delegate  (0) 2022.02.13
SOLID  (0) 2022.02.13

댓글