[iOS/Swift] JSON 다루기 / Codable / JSON Decoder / JSON Encoder
안녕하세요. 개발하는 정주입니다.
오늘은 iOS에서 JSON을 다루는 방법에 대해 포스팅하려고 합니다.
JSON 데이터를 넣는 구조체 정의와 인코딩, 디코딩에 대해 알아봅시다.
Codable
JSON을 다루기 전 Codable이 뭔지 알아야 합니다.
공식 문서에서는 Codable을 "Codable is a type alias for the Encodable and Decodable protocols."로 정의하였습니다.
즉 인코딩과 디코딩을 할 수 있는 프로토콜이라는 뜻이며 그러한 것을 수행하려고 할 때 채택하면 됩니다.
typealias Codable = Decodable & Encodable
typealias 역시 Encoable과 Decodable을 포함하는 형태입니다.
Codable을 사용하는 방법은 인코딩, 디코딩을 하고 싶은 class, struct, enum에서 Codable을 채택하여 구현하면 됩니다.
이때 주의할 점은 property를 json key와 동일한 이름으로 선언해야 한다는 점입니다. 이것은 아래에서 자세히 다루겠습니다.
struct Landmark: Codable {
var name: String
var foundingYear: Int
// Landmark now supports the Codable methods init(from:) and encode(to:),
// even though they aren't written as part of its declaration.
}
Encodable과 Decodable이 동시에 필요하지 않을 때는 둘 중 하나만 채택하는 것도 좋은 방법입니다.
struct Landmark: Encodable {
var name: String
var foundingYear: Int
}
struct Landmark: Decodable {
var name: String
var foundingYear: Int
}
CodingKey
일반적은 Codable을 채택한 struct, class 등은 키 값과 동일하게 property 이름을 정해야 합니다.
{
"name" : "Pear",
"points" : 250,
"description" : "A ripe pear."
}
예를 들어, 위와 같은 JSON을 담을 struct를 만들 땐
property 이름을 name, points, description으로 해야 한다는 의미입니다.
하지만 Swift의 코드 스타일과 외부 형식의 코드 스타일이 다를 수 있습니다.
대표적인 예로 Swift에서는 변수명에 _(언더바)를 사용하지 않죠.
이런 문제를 해결하기 위해 나온 프로토콜이 CodingKey 입니다.
타입 내부에 String 타입의 rowValue를 갖는 CodingKeys라는 이름의 enum을 선언하고
CodingKey 프로토콜을 채택, 준수하면 됩니다.
CodingKeys enum case 이름은 해당 property의 이름과 일치해야 합니다.
struct Landmark: Codable {
var name: String
var foundingYear: Int
var location: Coordinate
var vantagePoints: [Coordinate]
enum CodingKeys: String, CodingKey {
case name = "title"
case foundingYear = "founding_date"
case location
case vantagePoints
}
}
위 코드는 JSON key 값 title을 name에 넣겠다, founding_date를 foundingYear에 넣겠다는 것을 의미합니다.
원래는 title, founding_date로 선언했어야 하는 것을 CodingKey를 이용해 Swift 스타일에 맞게 작성한 것입니다.
JSON Encoder & Decoder
지금부터는 JSON을 다루는 예시를 살펴보겠습니다.
아래 예시는 공식 문서에 나와있는 예시이며 자기 스타일대로 직접 코드를 작성해보시는 것을 추천합니다.
Swift 4 이전에는 JSONSerialization 클래스를 이용하여 인코딩과 디코딩을 작업했으나
Swift 4부터는 JSONEncoder와 JSONDecoder 클래스가 생성되었습니다.
JSON을 인코딩할 때는 JSONEncoder 객체를 사용하면 됩니다.
참고로 outputFormatting을 prettyPrinted로 설정하면 JSON 형식대로 예쁘게 출력됩니다.
struct GroceryProduct: Codable {
var name: String
var points: Int
var description: String?
}
let pear = GroceryProduct(name: "Pear", points: 250, description: "A ripe pear.")
let encoder = JSONEncoder()
encoder.outputFormatting = .prettyPrinted
let data = try encoder.encode(pear)
print(String(data: data, encoding: .utf8)!)
/* Prints:
{
"name" : "Pear",
"points" : 250,
"description" : "A ripe pear."
}
*/
JSON을 디코딩할 때는 JSONDecoder 객체를 사용합니다.
struct GroceryProduct: Codable {
var name: String
var points: Int
var description: String?
}
let json = """
{
"name": "Durian",
"points": 600,
"description": "A fruit with a distinctive scent."
}
""".data(using: .utf8)!
let decoder = JSONDecoder()
let product = try decoder.decode(GroceryProduct.self, from: json)
print(product.name) // Prints "Durian"
참조
https://developer.apple.com/documentation/swift/codable
https://developer.apple.com/documentation/foundation/jsonencoder
https://developer.apple.com/documentation/foundation/jsondecoder
아직은 초보 개발자입니다.
더 효율적인 코드 훈수 환영합니다!
공감과 댓글 부탁드립니다.