Warning: 이해한 부분을 최대한 남기고 정리하려 남긴 글 입니다. 틀린 부분이 있을 수 있습니다. 이점 유의하고 읽어주시면 감사할 것 같습니다. 그리고 틀린 부분 알려주시면 바로바로 고치도록 하겠습니다.
Codable이 뭔가 했는데 Decodable
& Encodable
프로토콜의 별칭(typealias)를 뜻하더라구요.
그러니까 Codable은 Decodable과 Encodable을 준수하는 프로토콜로 봐도 무방합니다.
Decodable: 자신을 외부표현(JSON)으로 인코딩할 수 있는 타입
Encodable: 외부 표현(JSON)으로부터 자신을 디코드 할 수 있는 타입
만약 파싱하려는 JSON 파일이 같은 종류의 요소들로 이뤄져있다면 Codable
또는 Decodable
을 채택한 구조체를 활용하여 데이터를 읽어올 수 있다.
Codable을 채택한 구조체 전체에 해당되는 JSON 파일의 값을 파싱하고 싶을 때는 [구조체].self
를 사용하면 된다.
import Foundation
let json = """
[
{
"name": "Banana",
"points": 200,
"description": "A banana grown in Ecuador."
},
{
"name": "Orange",
"points": 100
}
]
""".data(using: .utf8)!
struct GroceryProduct: Codable {
var name: String
var point: Int
var description: String?
}
let decoder = Decoder()
let products = try decoder.decode([GroceryProduct].self, from: json)
구조체를 생성한 뒤 JSON에 해당되는 key에 매칭할 변수를 만들어 줘야 합니다. 변수의 이름과 key의 이름이 같아야 합니다.
NSDataAsset
는 Xcode의 모든 데이터 컨텐츠를 나타낸다. 그렇기 때문에 JSON파일이 Asset폴더에 저장되어있는 경우 해당 카탈로그로 접근해서 JSON파일을 가져온 뒤 파싱을 하면 된다.
접근 하기 위해서는 init?(name: )
메서드를 통해 해당 data asset을 먼저 초기화 후 해당 데이터 참조 값을 갖는 object를 리턴 받아야 합니다
init?(name: )메서드는 name에 해당되는 데이터가 있으면 object를 반환하고 해당되는 데이터가 없을 경우 nil을 반환합니다.
아래와 같은 방법으로 파싱할 수 있겠습니다.
먼저 init메서드를 통해 반환 되는 값이 옵셔널 값이기 때문에 guard let
구문으로 옵셔널 추출을 해 준 뒤
let decoder = Decoder()
guard let asset = NSDataAsset.init(name: "파일이름") else { return }
let products = try decoder.decode([GroceryProduct].self, from: asset.data)
asset.data
를 통해 asset폴더에 있는 데이터의 참조값을 가지고 있는 object의 데이터에 접근할 수 있다.
JSON파일의 key name은 camelCase가 아니고 product_name
이런식으로 작성되는 경우가 많다. 그러면 구조체에서 매치하기 위해서는 camelCase를 쓰지 않고 var produce_name
이라고 선언 해 줘야 하는데 그러면 애플스타일이 아니지요! 이를 해결하기 위해서 CodingKey
를 활용하면 된다.
struct GroceryProduct: Codable {
var name: String
var points: Int
var description: String?
private enum CodingKeys: String, CodingKey {
case name = "product_name"
case points = "product_cost"
case description
}
}
스위프트 변수의 이름과 JSON key의 이름을 애플스타일로 매칭시켜주기 위해 구조체 안에 nested Enum을 활용할 수 있습니다.
아래와 같은 Nested JSON 데이터 같은 경우 어떻게 모델을 구성하고 Parsing을 할 수 있을까?
{
"page": 1,
"items": [
{
"id": 1,
"title": "MacBook Pro",
"price": 1690,
"currency": "USD",
"stock": 0,
"thumbnails": [
"https://camp-open-market.s3.ap-northeast-2.amazonaws.com/thumbnails/1-1.png",
"https://camp-open-market.s3.ap-northeast-2.amazonaws.com/thumbnails/1-2.png"
],
"registration_date": 1611523563.7237701
}
]
}
먼저 해당 JSON에 매칭할 수 있는 아래와 같은 struct
모델을 구현하자.
struct MarketItemList: Decodable {
let page: Int
let items: [Items]
}
struct Items: Decodable {
let id: Int
let title: String
let price: Int
let currency: String
let stock: Int
let descriptions: String
let discountedPrice: Int?
let thumbnails: [String]
let registrationDate: Double
private enum CodingKeys: String, CodingKey {
case id
case title
case price
case currency
case stock
case descriptions
case discountedPrice = "discounted_price"
case thumbnails
case registrationDate = "registration_date"
}
}
더 복잡한 JSON파일을 파싱하는 방법을 아시고 싶으시면 아래 공식사이트 확인하시면 좋을 것 같습니다.↓
Using JSON with Custom Types | Apple Developer Documentation
[참고]:
Using JSON with Custom Types | Apple Developer Documentation