Codable - ehrldyd15/Swift_Skills GitHub Wiki
Codable
Codable이란?
Encodable과 Decodable을 합친 것이다.
Encodable은 data를 Encoder에서 변환해주려는 프로토콜로 바꿔주는 것
ex) 모델을 json으로 Encode
Decodable은 data를 원하는 모델로 Decode해주는 것
ex) json을 원하는 모델로 Decode
Codable은 프로토콜이기 때문에 채택을 해야 한다.
struct, enum, class 전부 채택이 가능하다.
예제를 통해 배워보자
struct User {
enum CodingKeys: String, CodingKey ✅ {
case id
case name
case birth
case phoneNum = "phone_num"
}
let id: Int
let name: String
let birth: String
let phoneNum: String
}
CodingKeys는 json key가 아닌 내가 원하는 이름으로 지정해줄 수 있게 해주는 프로토콜이다.
위 예제에서 실제 json key들이 id, name, birth, phone_num 이지만
내가 원하는 이름은 id, name, birth, phoneNum이다.
만약 json key와 내가 지정하는 이름이 같다면 case에 json key만 작성하면 된다.
Decodable
extension User: Decodable ✅ {
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
id = try container.decode(Int.self, forKey: .id)
name = try container.decode(String.self, forKey: .name)
birth = try container.decode(String.self, forKey: .birth)
phoneNum = try container.decode(String.self, forKey: .phoneNum)
}
}
Decodable은 프로토콜이니까 User stuct에서 채택해준다.
Decodable을 채택하면 무조건 init을 생성해야한다.
위와 같은 형태는 애플 문서에 나와있는 형식이다.
여튼 Decodable을 채택하고
func decode() {
let jsonString = """ ✅
[
{
"id": 1,
"name": "shark1",
"birth": "1999-03-17",
"phone_num": "010-2222-3333"
},
{
"id": 2,
"name": "shark2",
"birth": "1999-03-19",
"phone_num": "010-2222-3334"
},
{
"id": 3,
"name": "shark3",
"birth": "1999-03-20",
"phone_num": "010-2222-3353"
}
]
"""
let jsonData = jsonString.data(using: .utf8) ✅
do {
guard let jsonData = jsonData else { return }
let dataModel = try JSONDecoder().decode([User].self, from: jsonData) ✅
print(dataModel)
} catch let error {
print("에러: \(error)")
}
}
-
jsonString이라는 임의의 json형태인
string타입의 변수를 생성한다. -
decode를 하기 위해서는 Data타입이 필요하기 때문에 String타입을
Data로 변환시켜준다. -
JSONDecoder()을이용하여 decode를 [User]타입에 맞게 구현하면[Codable.User(id: 1, name: "A", birth: "1999-03-17", phoneNum: "010-2222-3333"), Codable.User(id: 2, name: "B", birth: "1999-03-19", phoneNum: "010-2222-3334"), Codable.User(id: 3, name: "C", birth: "1999-03-20", phoneNum: "010-2222-3353")]
User 모델에 맞게 decode가 된다.
Encodable
extension User: Encodable { ✅
func encode(to encoder: Encoder) throws{
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(id, forKey: .id)
try container.encode(name, forKey: .name)
try container.encode(birth, forKey: .birth)
try container.encode(phoneNum, forKey: .phoneNum)
}
}
Encodable은 Decodable의 반대로 하면 된다.
Decodable과 마찬가지로 Encodable을 채택한 후
func encode() {
let userObject = User(id: 1, name: "A", birth: "2000-03-02", phoneNum: "010-3434-2222") ✅
do {
let jsonData = try JSONEncoder().encode(userObject) ✅
let jsonString = String(data: jsonData, encoding: .utf8) ✅
guard let printJsonString = jsonString else { return }
print(printJsonString)
} catch let error {
print("에러: \(error)")
}
}
decode할 때와는 반대로
-
userObject라는 객체를 만든다.
-
JSONEncoder의 encode메서드를 이용하여 Data타입으로 만든다. -
String 타입으로 만든다.
그러면 아래와 같은 결과를 얻게된다.
{"id":1,"name":"A","birth":"2000-03-02","phone_num":"010-3434-2222"}
추가로 User struct처럼 타입이 명확한 경우에는
struct User: Codable { ✅
enum CodingKeys: String,CodingKey {
case id
case name
case birth
case phoneNum = "phone_num"
}
let id: Int
let name: String
let birth: String
let phoneNum: String
}
Encodable, Decodable을 따로 채택하지 않고, Codable만 채택해서 축약할 수 있다.
Codable은 typealias Codable = Encodable & Decodable
위에 언급했지만 타입이 명확하게 지정되어 있는 친구들만 가능하다.
struct안에 struct가 있다거나, Any타입이거나, [String:Any] 등 이런 친구들은 곤란하다.
참고자료
https://shark-sea.kr/entry/Swift-Codable-%EC%95%8C%EC%95%84%EB%B3%B4%EA%B8%B0?category=784184