[Swift] Codable을 이용해 JSON 처리하기

이남준·2021년 5월 21일
0
post-thumbnail
post-custom-banner

[Swift] Codable을 이용해 JSON 처리하기

Codable

우선 Codable 이란 JSON과 같은 외부표현으로 자신을 변환하거나 변환되는 타입입니다.

참고: https://developer.apple.com/documentation/swift/codable/

이게 무슨 말이냐면, Swift class, struct, enum 타입이 Codable을 채택하면 JSON 데이터를 변환 시켜 자신의 타입으로 바꿀 수 있고 자신을 JSON 형태로 바꿀 수도 있다는 뜻입니다!

Codable 은 또한

Codable

Decodable, Encodable을 동시에 포함하는 typealias이기 때문에 Codable만 채택해줘도, 두 프로토콜을 모두 구현할 수 있습니다.

Example

설명만 보면 이해하기 힘드니 간단한 예시를 보겠습니다.

struct Person: Codable {
    var name: String
    var age: Int
}

여기 Codable을 채택하고 있는 아주 간단한 struct Person이 있습니다.
그 뜻은 JSON을 받아와서 Person을 만들 수도 있고, 반대도 가능하다는 뜻입니다.

Encoding

먼저 JSONEncoder를 통해 Person을 JSON으로 인코딩 해보겠습니다.

let nj = Person(name: "NJ", age: 10)

let encoder = JSONEncoder()
let encodedData = try? encoder.encode(nj)

JSONEncoder객체를 하나 만들고, .encode()Person객체를 넣어 줌으로써 간단하게 인코딩이 되었습니다.

어 그럼 바로 JSON 형태의 데이터를 쓸 수 있겠네?

print(encodedData)
// Optional(22 bytes)

라고 print를 해보면 이상한 결과가 나옵니다.
왜냐하면 .encode()메소드는 Encodable을 준수하고 있는 타입을 파라미터로 받아서 Data타입으로 리턴을 해주기 때문입니다.

그렇기 때문에 한번 더, Data타입을 JSON String으로 바꾸는 과정을 거쳐야 합니다.

if let jsonData = encodedData, let jsonString = String(data: jsonData, encoding: .utf8){
    print(jsonString)  // {"name":"NJ","age":10}
}

이렇게 String(data:, encoding:)메소드를 사용해 변환할 수 있습니다.
하지만 최종 String이 한줄로 출력되서 가독성이 별로 좋지 않은데,

{
  "name" : "NJ",
  "age" : 10
}

이런식으로 리턴을 받고 싶으면

let encoder = JSONEncoder()
encoder.outputFormatting = .prettyPrinted

이렇게 인코더의 아웃풋 포맷을 지정해주기만 하면 됩니다.

그래서 인코딩 과정을 요약하면,
1. JSONEncoder 객체 생성
2. .encode() 메소드를 통해 Data타입 리턴 받기
3. 리턴 받은 DataString으로 변환

Decoding

다음은 보통 API를 통해 데이터를 받는 일이 더 많기 때문에 더 자주쓰이는 JSON String을 받아서 내가 원하는 타입으로 변환하는 것을 해보겠습니다.

우선 예시로 사용할 JSON을 위의 인코딩 예시에서 생성한 것을 사용하겠습니다.

{
  "name" : "NJ",
  "age" : 10
}

Decoding을 하는 것도 어렵지 않게 위 인코딩 과정을 거꾸로 실행해주면 됩니다.
1. JSONDecoder 객체 생성
2. StringData로 변환
3. .decode() 메소드를 통해 인스턴스 리턴 받기

// JSONDecoder 객체 생성
let decoder = JSONDecoder()

// 사용할 String
let dataString = 
    """
    {
    "name" : "NJ",
    "age" : 10
    }
    """

// String 을 Data로 변환
let data = dataString.data(using: .utf8)!

// Decoding
let decodedData = try? decoder.decode(Person.self, from: data)

이렇게만 하면 Person타입의 객체 decodedData를 만들 수 있습니다.

그런데 .decode()메소드의 파라미터 중 Person.self가 있는 이유는,

 /// Decodes a top-level value of the given type from the given JSON representation.
    ///
    /// - parameter type: The type of the value to decode.
    /// - parameter data: The data to decode from.
    /// - returns: A value of the requested type.
    /// - throws: `DecodingError.dataCorrupted` if values requested from the payload are corrupted, or if the given data is not valid JSON.
    /// - throws: An error if any value throws an error during decoding.
    open func decode<T>(_ type: T.Type, from data: Data) throws -> T where T : Decodable

.decode()메소드의 원형을 봤을 때, 첫번째 파라미터로 decode할 값의 타입을 받기 때문입니다.

이상으로 Codable을 이용해 간단하게 JSON을 처리하는 방법에 대해 알아보았습니다.

참고: https://zeddios.tistory.com/373, https://medium.com/@Lukaz32/swift-4s-codable-protocol-b851b5b5cbd9

profile
iOS 개발자의 기록
post-custom-banner

0개의 댓글