본문 바로가기

iOS/Swift

Swift) Codable - JSON을 쉽게 Encoding / Decoding 하자

 

 

안녕하세요 :) 소들입니다

오늘은 대망의 Codable을 다뤄보려고 합니다...

왜 대망이냐면.....

 

Swift로 개발한다고 하면서 Codable을 사용 안해본 개발자는

없을테니까............ 😱ㄴㅏ야 나~~~

쨌든 그런 이유에서 이번엔 Codable의 사용법에 대해 다뤄볼 거예요!!!!!!!

 

만약 JSON이 뭔지 모르시는 분이라면,

JSON이 도대체 뭘까 이  포스팅부터 보고 오셨으면 좋겠어요!! :)

 

간단한 사용법에 대해 알아봅시다 :)

모든 포스팅은 편의 말투로 합니다~!!

 

 

 

 

1. Codable이 도대체 뭘까

 

Codable이 그래서 도대체 뭔지 정의부터 얘기하고 가자면

 

Swift4부터 추가된 프로토콜로,

JSON 데이터를 간편하고 쉽게 Encoding / Decoding 할 수 있게 해준다

 

뭐 그런 내용임..!

한 마디로 서버와 데이터를 주고 받을 때 보통 JSON으로 주고 받잖음?

이 JSON 데이터를 다룰 때 보통 직접 다룰 수도 있고,

SwiftyJSON과 같은 라이브러리를 통해서 다룰 수도 있잖음??

 

근데 이 Codable을 이용하면, 

직접 다루거나 라이브러리를 사용하는 것보다 훨씬!! 간편하게?

JSON 데이터를 다룰 수 있음 !

 

그러면 Codable의 사전적 정의를 살펴봤으니,

실제 코드로는 어떻게 정의되어 있는지 보자 :)

 

 

 

 

Codable은 DecodableEncodable로 이루어져 있다고

 typealias로 정의되어 있음

그럼 Decodable과 Encodable이 뭐냐

 

 

 

 

뭔진 모르겠지만 일단 protocol이군 👀

따라서 Codable이란,

 

Encodable & Decodable 프로토콜을 준수하는 프로토콜이다

 

정도가 되겠음

Struct, Class, Enum 모두 Codable을 채택할 수 있음!!!

 

그럼 Codable을 이용해서 도대체 어떻게 쉽게 Encoding / Decoding 하는지

살펴보잣

 

 

 

 

2. Codable을 이용한 Encoding

 

먼저, Encoding을 먼저 다뤄보겠음

사실 앱을 개발하다 보면 JSON 데이터를 Decoding 하는 일은 많지만

Encoding 하는 일은 별로 없을 거란 말이지?

 

그치만 난 실제로 Encoding 해서 Server에 통신하는 작업을

Objective-C를 통해 해봤기 때문에 Encoding도 다룰 것임

(그러나 깊게 다루진 않게따)

 

먼저, Encoding이 무엇이냐 정의부터 내리면

 

 내가 원하는 struct, class, enum 등등의 인스턴스를

JSON 형태의 Data로 만들어주는 것

 

예제로, Encoding할 데이터를 Struct로 하나 만들고

Sodeul이라는 구조체 변수도 생성해보겠음

 

 

struct HumanCodable {
    var nameString
    var ageInt
}

let sodeul: Human = .init(name: "Sodeul", age: 26)

 

 

자, 여기서 중요한 것은, 

Codable을 이용해 JSON으로 Encoding 하고 싶을 경우,

반드시 Codable이라는 Protocol을 준수하고 있어야함

 

자, 그럼 이제 Sodeul이라는 구조체 변수를 Encoding 해보겠음

Codable을 이용하면 얼마나 간단하냐면

 

 

let data = tryJSONEncoder().encode(sodeul)

 

 

이렇게 한 줄로 끝남........ㅎ

실제 data를 String으로 변환시켜 출력해보면

 

 

데이터가 잘 만들어져 있음!!!!

 

JSONEncoder 클래스에다가 encode 메서드를 호출해주는데,

이때 codable을 준수하는 구조체 타입인 sodeul을 넣어주면

JSON 데이터를 알아서 뚝딱 만들어줌 ㅎㅎㅎㅎㅎ 매우 간편

 

이 encode 함수를 좀 더 자세히 보자면

 

 

 

 

Generic으로 선언되어 있는데,

이 T는 Encodable이라는 프로토콜을 준수하고 있어야만

encode라는 메서드를 사용할 수 있음

 

우리는 Codable(Encodable + Decodable)을 사용했기 때문에

encode라는 메서드를 사용할 수 있음!

 

또한 throws라고 되어있는 것 처럼, Encoding 중 에러가 발생할 수 있기 때문에

반드시 try와 같이 써주어야 함!!!

 

만약, Codable 프로토콜을 채택하지 않고 사용하려고 한다면,

 

 

 

 

encode 메서드는 Human 구조체가 Encodable을 준수하도록 요구한다

라는 메세지가 뜨면서 안됨 ㅎㅎㅎ 

 

쨌든 Codable을 이용하면 

이렇게나 간단하고 단 한 줄 만으로 JSON 데이터를 만들 수 있따.........

👍

 

Encoding은 실제 많이 사용하진 않으니 이정도로만 다루고,

질리도록 사용하는 Decoding을 다뤄보겠음

 

 

 

 

3. Codable을 이용한 Decoding

 

이번엔 Decoding을 다뤄보겠음!!!!!!!!!!!

실제로 우리가 가장 많이 사용하는 것은 이 Decoding이기 때문에.. ㅎㅎ;

좀 더 깊게 문제점, 예외처리 등등에 대해서 다뤄보겠음

 

자, 먼저 Encoding은 내가 원하는 struct, class, enum 등등의 인스턴스를

JSON 형태의 Data로 만들어주는 것이랬음

그럼 Decoding은 머냐거?

 

JSON 형태의 Data를 struct, class, enum 등의 인스턴스에

자동으로 파싱

 

해주는 것임

 

이해가 안 갈 수 있으니, 예제로 보자 :)

자 또 다음과 같이 Codable을 준수하는 구조체가 있음

 

 

struct HumanCodable {
    var nameString
    var ageInt
}

 

 

이번엔, 만약 서버에서 name과 age가 담긴 JSON 데이터를 준다고 생각해보셈

지금은 서버와 작업하는 것이 아니니 다음과 같이  data라는 변수를

 

 

let data = """
{
    "name" : "Sodeul",
    "age"  : 26
}
""".data(using: .utf8)!

 

 

서버가 준 JSON 데이터라 생각하고 고고

그럼 나는 이제 이 data를 Human이란 구조체 변수에 Decoding을 하고 싶다면

 

 

let sodeul = tryJSONDecoder().decode(Human.self, from: data)

 

 

자, 이렇게 써주면 또 단 한 줄 만으로 파싱이 됨~_~

결과값을 보면

 

 

 

 

Sodeul이란 객체에 JSON Data 값이 아주 잘 파싱되어 있음!!!!

먼저, 어떻게 파싱되는지는 보기 전에 왜 함수가 저런 모양인지

decode 함수 원형부터 살펴보면,

 

 

 

 

Encode와 마찬가지로 Generic TDecodable을 준수하고 있어야 하고,

Decoding 중에 실패할 수 있기 때문에, 반드시 try랑 함께 써주어야 함

 

또한 type 파라미터는 T.Type을 받기 때문에, 

우리가 파싱하고자 하는 클래스 Human의 type을 써줘야 해서 Human.self를 써준 것임

 

자, 그럼 어떤 방식으로 파싱이 되는지를 보면 :)

 

Human 타입의 구조체를 하나 만들고,

JSON Data의 Key 값동일한 이름구조체 변수value에 값을 파싱

그리고 파싱된 구조체를 리턴

 

좀 더 쉽게 설명하자면,

 

 

 

 

이런 식으로

 JSON Data의 "Key" 값(name, age)가 구조체의 변수 이름(name, age)와 동일하면,

변수의 값(name, age)에 Value("Sodeul", 26)을 파싱하는 것임

 

따라서

 

JSON Data의 Key 값은 Codable을 따르는 타입(Human 구조체)의 멤버 이름과

1대1 매칭 되어야만 문제 없이 사용할 수 있다

 

그럼........... 여기서 궁금증이 생김

그럼 서버에서 주는 Key 값에 무조건 맞춰서 변수명을 사용해야 하나..=-=?

Decodable의 특징으로 설명하겠음

 

 

 

3-1. CodingKey

 

만약 서버에선 Name 이라는 Key를 사용한다고 침

 

 

struct HumanCodable {
    var nameString
}

let data = """
{
    "Name" : "Sodeul",
}
""".data(using: .utf8)!

 

근데 변수명은 대문자로 시작하지 않으니까..

우리가 name이라고 이름을 바꿔줘버리면!!!!!!

1대1 매칭이 되지 않기 때문에

 

 

 

 

Decoding Fail로 간주되어, nil로 떨어짐

 

따 라 서

만약 Key 값에 대응하는 이름을 바꿔주고 싶다면, 

 

CodingKey

 

라는 프로토콜을 이용해서 Key의 이름이 바뀌었다는 걸 명시해줘야 함

어디에 명시하냐?? 

CodingKey을 준수하는 타입에 enum으로 다음과 같이 명시해줌

 

 

struct HumanCodable {
    var nameString
}
    enum CodingKeysStringCodingKey {
        case name = "Name"
    }
}

 

 

이런 식으로,

Name이라는 키를 name이란 이름으로 받겠다고 정의해줘야 함

(귀찮)

 

 

 

3-2. 특정 Key-Value가 없이 오는 경우

 

만약 서버에서 데이터를 던져주는데,

어느 순간 특정 Key-Value가 누락되어서 올 수도 있잖음?

 

 

struct HumanCodable {
    var nameString
}

let data = """
{
}
""".data(using: .utf8)!

 

이렇게 data에 name이라는 Key-Value가 누락되어

아무 것도 안와버린 것임

그러면 Codable은 이를 어떻게 처리하냐?

 

 

 

 

에러ㅋ 진짜 예민한 친구네

따라서 이럴 경우를 대비해서 2가지 처리를 할 수 있는데,

 

 

① Key가 없을 경우를 대비해 직접 Decoding 함수를 작성한다

 

먼말이냐면, JSON을 Decoding 할 때

 init(from decoder: Decoder)

이 함수가 호출되는데, 우리가 이 함수를 직접 건드려서

 

야 키 없으면 이 값으로 대체하자!!!

 

하고, 우리가 기본 값을 셋팅해준다는 것임

어떻게 사용하는진 코드로 보여주겠음!!!

 

 

struct HumanCodable {
    var nameString

    init(from decoder: Decoderthrows {
        let values = try decoder.container(keyedBy: CodingKeys.self)
        name = try? values.decode(String.self, forKey: .name)) ?? ""
    }
}

 

이렇게 정의해주면  name이라는 Key가 없이 오더라도,

Decoding Fail이 아닌 우리가 미리 정의해둔 "" 값이 name에 들어감

 

 

② 변수를 옵셔널로 선언하자

 

사실....... 맘편하게 Optional로 선언하면

 

 

struct HumanCodable {
    var nameString?
}

 

문제 해결 :)))...

하지만 나중에 Optional Binding 하기가 귀찮겠찌

 

 

 

3-3. Value 값이 null인 경우

 

마지막으로 다뤄보겠음

JSON Data에선, Value 값이 null 일 수가 있는데,

 

 

let data = """
{
    "name" : null
}
""".data(using: .utf8)!

 

 

Codable은 Value 값이 null일 경우

 

 

 

 

또.. 에러;;

얘 개복치임?? 툭 건들면 에러여;

쨌든 이럴 땐 단순하게 변수를 Optional로 선언하면 됨

 

 

struct HumanCodable {
    var nameString?
}

 

그럼 해결 :)

 

 

 

 

.

.

.

오늘은... 나만 모르고 모두 아는 Codable에 대해 다뤄봤어여 ...

아 넘 힘들다.. 이 외에도 더 다루고 싶은 내용이 있지만

넘 길어지기 때문에,, 이번엔 기초만 다룬단 느낌으로ㅜㅜㅜㅜ

오늘 공부하며 느낀점..

 

Codable... 편하지만.. 개복치다..

 

 

솜네일



Calendar
«   2024/04   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
최근 댓글
Visits
Today
Yesterday