[iOS] Codable에 관하여
Codable이란 ?
A type that can convert itself into and out of an external representation. - Apple Doc
외부 표현을 변환할때 사용한다.
우리가 사용하는 이유는 JSON 데이터를 우리가 만들 애플리케이션에서 사용하기 편하도록 객체에 맵핑하기 위해 사용한다.
Decodable : 자신을 외부표현으로부터 디코딩할수있는 타입.
Encodable : 자신을 외부표현으로 인코딩 할수있는 타입.
JSON기준에서
서버파트에서 JSON데이터를 보내 줄 것이고, 현재 나와있는 거의 모든 API들이 JSON으로 뿌려준다.
//JSONData
{
"a":"나는 a입니다.",
"b":"나는 b입니다."
}
//Codable로 구성된 모델
struct Sample: Codable{
var a:String
var b:String
enum CodingKeys: String, CodingKey {
case a
case c = "b"
}
}
JSON을 Codable로 처리할 때, 밑줄 표기법을 낙타 표기법으로 바꾼다거나 JSON에 있는 이름과 완전히 다른 이름으로 사용하려면 CodingKey를 따로 정의하면 된다.
let sampleDecoding = try! JSONDecoder().decode(Sample.self, from: sampleData)
앞서 Codable 정의에서 설명한 것 처럼 우리는 외부 표현 , 즉 JSON을 우리 애플리케이션에서 사용하기위해서 Decoding해서 사용해야한다.
JSONDecoder 를 사용할 때 error를 검출하기 위해서 try 이를 사용한다.
(정확한 데이터를 사용한다면 강제언래핑 처럼 try! 를 사용, 옵셔널이라면 try? 를 사용하고 데이터를 사용할때 if let 문으로 옵셔널 해제를 해줘야한다.)
JSONData 가 바뀌어 원래 지정했던 키가 없을 경우가 있으므로
모델 구조체 자체에서 JSON데이터를 디코딩 해서 keyNotFound 에러를 처리할수있다.
키와 값이 없을 경우를 미리 정해놓는 것
import UIKit
//바뀐 JSON데이터
let sample1Data = """
{
"a": "aa"
}
""".data(using: .utf8)!
//아까 설정한
struct Sample: Codable{
var a:String
var c:String
enum CodingKeys: String, CodingKey {
case a = "a"
case c = "b"
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
a = try values.decodeIfPresent(String.self, forKey: .a) ?? "값이없습니다."
c = try values.decodeIfPresent(String.self, forKey: .c) ?? "값이없습니다."
}
}
let data = try! JSONDecoder().decode(Sample.self, from: sample1Data)
init(from decoder: Decoder)에 a 와 c 라는 key 값이 매핑 됬을 경우 를 처리 해놨다.
JSON데이터에 key "a"값만 보내주고 있으므로 "c"값에 대한 처리가 필요하다.
try 를 해서 error 즉 실패 했을 경우 "값이 없습니다"를 key의 value에 할당해서 보여주는것이다.
JSON Array
{
"status": 200,
"message": "모든 글 조회 성공",
"data": [
{
"id": 11,
"title": "글 제목2",
"contents": "내용내용내용",
},
{
"id": 20,
"title": "10",
"contents": "",
}
]
}
위 JSON데이터 처럼 배열 형태의 데이터가 있을 때는
struct ArraySample : Codable {
var status: Int
var message: String
var userData: [UserArray]
enum CodingKeys: String, CodingKey {
case status
case message
case userData = "userArray"
}
}
struct UserArray : Codable {
var id: Int
var title: String
var contents: String
}
let arraySampleDecoding = try! JSONDecoder().decode(ArraySample.self, from: arrayJSONData)
print(arraySampleDecoding)
이렇게 모델을 중첩해서 사용하면 된다.
[tip] 한번에 JSON객체 만들 수 있는 사이트 : www.json4swift.com