[Swift] Codable - Encoding 방법

728x90

 

 

이번 포스트는 CodableEncodable에 대해 알아 보도록 하겠습니다.

 

먼저 애플의 문서를 확인해보면

💡 A type that can convert itself into and out of an external representation.

외부 표현으로 변환하거나 외부 표현으로 변환할 수 있는 유형이라고 하는데

쉽게 이야기하자면, 자신을 외부 표현으로 인코딩할 수 있고, 자신을 외부 표현으로 부터 디코딩할 수 있다는 이야기입니다.

주로 JSON을 이용할 때 사용되기 때문에 외부 표현을 JSON데이터로 생각하면 더 쉽게 이해가 될것 같습니다.

 

public typealias Codable = Decodable & Encodable

Codable은 EncodableDecodable로 이루어져 있습니다.

먼저 JSON으로 인코딩하기 위해서는 Encodable 프로토콜을 채택해야 됩니다

반대로 JSON으로부터 디코딩되는 형식은 Decodable 프로토콜을 채택해야 됩니다.

 

 

Encodable


JSONEncoder는 모든 형식을 JSON으로 바꿀수 있습니다.

따라서 인스턴스에 저장되있는 데이터를 JSONEncoder를 이용해서 JSON으로 바꿔보도록 하겠습니다.

Encodable과 Decodable을 동시에 가지고있는 Codable을 채택하며 진행하도록 하겠습니다.

 

💡 Codable은 Encodable, Decodable 두 가지를 가지고 있지만, 인코딩만 하면 Encodable, 디코딩만 하면 Decodable만 채택해서 사용 가능합니다.

 

struct Person: Codable {
   var name: String
   var age: Int
   var birthDate: Date
   var address: String?
}

let person = Person(name: "Jinnify",
                    age: 29,
                    birthDate: Date(timeIntervalSince1970: 0),
                    address: "동대문구 답십리")

Person이라는 인스턴스가 존재한다고 했을때,

JSONEncoderencode를 통해 Binary Data로 인코딩이 된 것을 볼 수 있습니다.

보통 서버로 데이터를 보낼 때는 Binary Data를 그대로 전달 합니다.

let encoder = JSONEncoder()

do {
  let jsonData = try encoder.encode(person)
  print(jsonData)
} catch {
  print(error)
}

/* 

결과
112 bytes
*/

 

# Key를 snake_case로 변경하는 방법

기본적으로 JSONEncoder는 속성 이름을 Key로 변환할때, lowerCamelCase 규칙을 사용합니다.

하지만 인코딩할때 Key를 snake_case로 변경이 가능한 옵션이 존재합니다.

 

먼저 위의 예제는 바이트 결과값이 보이는데 key의값이 잘 인코딩됬는지 임의적으로 String으로 변환해서 확인해보도록 하겠습니다.

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

do {
  let jsonData = try encoder.encode(person)

  if let jsonStr = String(data: jsonData, encoding: .utf8) {
    print(jsonData)
  }
} catch {
  print(error)
}

/* 
{
  "name" : "Jinnify",
  "age" : 29,
  "address" : "동대문구 답십리",
  "birthDate" : -978184077
}
*/

결과 값을 보면 JSON의 Key 값이 default로 lowerCamelCase로 인코딩이 된걸 볼 수 있습니다.

 

 

  • keyEncodingStrategy
let encoder = JSONEncoder()
encoder.keyEncodingStrategy = .convertToSnakeCase
do {
  let jsonData = try encoder.encode(person)

  if let jsonStr = String(data: jsonData, encoding: .utf8) {
    print(jsonData)
  }
} catch {
  print(error)
}

/* 
{
  "name" : "Jinnify",
  "age" : 29,
  "birth_date" : -978307200,
  "address" : "동대문구 답십리"
}
*/

모든 문자가 소문자로 구성되고 단어와 단어 사이에 _ 로 구성된 것을 볼 수 있습니다.

만약 서버에 전달할때 서버에선 snake_case를 사용한다면 변경해서 전달해주면 좋겠죠?

 

 

# Date Encoding

date타입의 형식을 인코딩하는 방법에 대해 알아보도록 하겠습니다.

{
  "name" : "Jinnify",
  "age" : 29,
  "birth_date" : -978307200,
  "address" : "동대문구 답십리"
}

위의 결과값을 보면 음수값이 있는걸 볼수 있는데 date가 저런 숫자로 되있으니까 가독성이 떨어지죠

보통 ISO 8601인코딩방법과 Custom Formatter를 이용해서 인코딩 하는 방법이 존재합니다.

💡 Date(timeIntervalSince1970: 0)로 표현을 해서 인스턴스에 저장되었는데, 이것의 의미는 1970년 1월 1일부터 2001년 1월 1일까지의 시간 차이를 초로 변환한 숫자입니다.

 

JSONEncoder dateEncodingStrategy 옵션을 이용합니다.

 

  • ISO 8601 방법

보통 ISO 8601표준을 사용합니다.

let encoder = JSONEncoder()
encoder.dateEncodingStrategy = .iso8601

do {
  let jsonData = try encoder.encode(person)

  if let jsonStr = String(data: jsonData, encoding: .utf8) {
    print(jsonData)
  }
} catch {
  print(error)
}

/* 
결과

{
  "name" : "Jinnify",
  "age" : 29,
  "address" : "동대문구 답십리",
  "birthDate" : "1970-01-01T00:00:00Z"
}
*/

"birthDate" : "1970-01-01T00:00:00Z" 형식으로 제대로 인코딩 된걸 볼 수있습니다.

 

 

  • Custom Formatter 방법
let formatter = DateFormatter()
formatter.dateFormat = "yyyy/MM//dd"
encoder.dateEncodingStrategy = .formatted(formatter)

do {
  let jsonData = try encoder.encode(person)

  if let jsonStr = String(data: jsonData, encoding: .utf8) {
    print(jsonData)
  }
} catch {
  print(error)
}

/* 
결과

{
  "name" : "Jinnify",
  "age" : 29,
  "address" : "동대문구 답십리",
  "birthDate" : "1970\/01\/\/01"
}
*/

 

 

JSONEncoder를 이용해서 JSON형태의 Binary Data로 인코딩 하는 방법과

keyEncodingStrategy를 통한 snake_case로 변환 하는 방법
dateEncodingStrategy를 통한 date 인코딩 방법에 대해 알아보았습니다.

 

 

다음은 Codable의 Decodable을 이용해서 Decoding하는 방법에 대해 포스트 올리겠습니다.