JSON Decoing with Codable
이전에 작성한 포스팅에서 간단한 JSON을 Codable과 JSONDecoder를 이용해 파싱하였다.
https://wlgusdn700.tistory.com/50?category=913317
하지만, 프로젝트를 진행하다보면 서버에서 내려준 JSON(Key:Value) 중에 굳이 없어도 되는 값들이 존재한다.
"""
{
id: 10,
name: "tree",
nation: "대한민국"
....
}
"""
해당 JSON을 불러오고 여기서 id와 name만 사용한다고 가정하자.
필요없는 Key&Value는 선언하지 않고 Decodable을 채택/준수하면 된다.
struct Person: Decodable{
let id: Int
let name: String
//property 명과 key가 같기 때문에 CodingKeys를 작성하지 않아도 된다.
// enum CodingKeys: String, CodingKey{
//
// }
}
struct Person2: Decodable{
let identifier: Int
let nickname: String
enum CodingKeys: String, CodingKey{
case identifier = "id"
case nickname = "name"
}
}
Nested Decodable
"""
{
"id": 11,
"name": "tree",
"nation": "대한민국",
"company": {
"name": "네카라쿠",
"industry": "IT",
....
}
....
}
"""
위의 JSON이 있다고 가정하자.
만약 내가 필요한 Key&Value가 name, companyIndustry 2가지가 필요하다고 가정하자.
기존의 방식을 사용하면 Person이라는 struct안에 Company라는 struct를 하나 더 두어서 구현하는 방식이 있다.
(물론 해당 방식도 틀리다고 생각하지는 않는다.)
struct Person: Decodable{
let name: String
let company: Company
struct Company: Decodable{
let industry: String
}
}
이렇게 구현 시, industry라는 property에 접근하기 위해서는
person.company.industry 로 접근해야 한다. 사실 2-depth밖에 되지 않기 때문에, 불편해 보이지는 않는다.
더 심한 예를 들어보자.
"""
{
"httpDomain": "www......",
"response": {
...
"person":{
"id": 29,
"name": "tree",
"company": {
"industry": "IT",
.....
}
}
.....
}
}
"""
depth를 한단계 더 추가하였다. (실제 프로젝트에서는 더 깊고, 배열 등의 자료구조까지 들어간다면 훨씬 복잡해진다.)
(나는 name과 industry만 필요한데, 굳이 Response, Person, Company라는 struct를 만들어야하네...? 코드가 너무 길어지는데..?)
사실 response.person.company.industry 를 짧게 줄이는 방법은 여러가지가 있을 것이다.
1. computed Property
읽기 전용 computedProperty를 선언한다.
struct Response: Decodable{
....
var industry: String{
person.company.industry
}
....
}
2. Subcript
배열인 경우에는 서브스크립트를 사용해서 가져올 수 있다.
3. init(from decoder: Decoder)
struct Response: Decodable{
.....
let name: String
let industry: String
enum CodingKeys: String, CodingKey{
case name
case response
case person
case company
case industry
}
init(from decoder: Decoder) throws{
//가장 큰 {}가 있는 영역 -> {}를 컨테이너라고 생각하는 것이 이해하기 쉬웠다.
let values = try decoder.container(keyedBy: CodingKeys.self)
//response가 차지하고 있는 {}가 있는 영역
let response = try values.nestedContainer(keyedBy: CodingKeys.self, forKey: .response)
//response 영역 내에 있는 name을 파싱
self.name = try response.decode(String.self, forKey: .name)
//response 영역 내에 있는 person 영역
let person = try response.nestedContainer(keyedBy: CodingKeys.self, forKey: .person)
//person 영역 내에 있는 company 영역
let company = try person.nestedContainer(keyedBy: CodingKeys.self, forKey: .company)
//company 영역 내에 있는 industry를 파싱
self.industry = try company.decode(String.self, forKey: .industry)
//물론 한번에 작성해도 된다.
self.industry = try response.nestedContainer(keyedBy: CodingKeys.self, forKey: .person)
.nestedContainer(keyedBy: CodingKeys.self, forKey: .company)
.decode(String.self, forKey: .industry)
}
.....
}
이렇게 작성하게 되면 여러개의 struct를 굳이 만들지 않고도 industry를 최상단 struct에서 사용할 수 있다.
또한, String이나 Int 그리고 모든 Key&Value에서 struct에 저장할 때! 변경/조작하고 싶다면 init(from:)에서 조작도 가능하므로
더 폭넓게 사용할 수 있다.
'Swift' 카테고리의 다른 글
[Swift] DI: 의존성 주입 (Dependency Injection) in iOS/Swift (0) | 2021.11.09 |
---|---|
[Swift] Codable-CodingKey 을 이용해 JSON 파싱하기 (0) | 2021.01.25 |
[Swift] 상속 - 스위프트 언어 및 문법(13) - feat.야곰's Swift Programming (0) | 2021.01.19 |
[Swift] 서브스크립트 - 스위프트 언어 및 문법(12) - feat.야곰's Swift Programming (0) | 2021.01.18 |
[Swift] 모나드 - 스위프트 언어 및 문법(11) - feat.야곰's Swift Programming (0) | 2021.01.18 |