JSON 데이터는 JavaScript Object Notation으로 key:value 쌍 형식으로 이루어진 데이터입니다
JSON 데이터 만드는 방법
다음은 JSON 데이터를 만드는 방법입니다. JSONSerialization을 사용하면 구현한 JSON 형식 데이터를 JSON 데이터로 바꿀 수 있습니다.
추가 설명으로 try?로 설정하면 do catch를 사용하지 않아도 됩니다. 하지만 반환되는 데이터가 optional이 되는 것을 명심합시다.
func getJSONData() -> Data? {
let dictionary: [String:Any] = [
"id" : "12345",
"name": "Yoon",
"points" : 5,
"isPremium" : true
]
let jsonData = try? JSONSerialization.data(withJSONObject: dictionary)
return jsonData
}
JSON decode 하는 방법
JSON 데이터를 decode 하려면 우선 Decodable 프로토콜을 준수해야합니다.
그렇기 위해서는 init(from decoder: any Decoder) 초기화 함수를 사용해야 하는데 이때 다음과 같이 만들 수 있습니다.
enum CodingKeys: String, CodingKey {
case id
case name
case points
case isPremium
}
init(from decoder: any Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.id = try container.decode(String.self, forKey: .id)
self.name = try container.decode(String.self, forKey: .name)
self.points = try container.decode(Int.self, forKey: .points)
self.isPremium = try container.decode(Bool.self, forKey: .isPremium)
}
decoder container는 데이터를 가지고 있는 컨테이너를 의미하며 decoder.container의 keyedBy는 Decode할 데이터의 모든 딕셔너리 Key 값을 의미합니다. 그렇게 하기 위해서 CodingKey 프로토콜을 준수하는 enum 열거형을 만들며 딕셔너리의 키값은 String 이므로 String을 붙여줍니다 (생략 가능)
decode(decode할 타입, key값)으로 decode할 수 있도록 만듭니다.
init(from decoder: any Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.id = try container.decode(String.self, forKey: .id)
self.name = try container.decode(String.self, forKey: .name)
self.points = try container.decode(Int.self, forKey: .points)
self.isPremium = try container.decode(Bool.self, forKey: .isPremium)
}
이후 데이터를 다음과 같이 Decode할 수 있으며 위에서 init(from decoder:) 로 설정한대로 디코딩을 하게 됩니다.
func getData() {
guard let data = getJSONData() else { return }
do {
self.customer = try JSONDecoder().decode(CustomerModel.self, from: data)
} catch {
print("decoding error: \(error)")
}
}
JSON 데이터로 Encode 하기
JSON 데이터로 인코딩하기 위해서는 Encodable 프로토콜을 준수해야 합니다. 이후 init(from decoder: any Decoder) 함수를 만들어 Decode를 하기 위한 로직을 설정해줍니다.
container.encode()에서 id, name, points, isPremium은 전부 구조체에서 갖고 있는 데이터를 의미하며 키값은 CodingKeys를 사용하여 인코딩합니다.
struct CustomerModel: Identifiable, Decodable, Encodable {
let id: String
let name: String
let points: Int
let isPremium: Bool
...
func encode(to encoder: any Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(id, forKey: .id)
try container.encode(name, forKey: .name)
try container.encode(points, forKey: .points)
try container.encode(isPremium, forKey: .isPremium)
}
위에 설정을 하였으면 아래처럼 데이터를 인코딩할 수 있습니다.
func getJSONData() -> Data? {
let customer = CustomerModel(id: "1", name: "KIM", points: 87, isPremium: false)
let jsonData = try? JSONEncoder().encode(customer)
return jsonData
}
매우 간편한 Codable
Codable은 Decodable + Encodable 입니다. Codable을 사용했을 때 장점은 바로 위에서 한 작업들을 전부 다 코드 뒤에서 수행한다는 것입니다. 이것은 아래와 같은 CodingKey, init(from decoder:), func encode(to encoder:) 를 모두 생략할 수 있게 만듭니다.
struct CustomerModel: Identifiable, Decodable, Encodable {
let id: String
let name: String
let points: Int
let isPremium: Bool
init(id: String, name: String, points: Int, isPremium: Bool) {
self.id = id
self.name = name
self.points = points
self.isPremium = isPremium
}
enum CodingKeys: String, CodingKey {
case id
case name
case points
case isPremium
}
init(from decoder: any Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.id = try container.decode(String.self, forKey: .id)
self.name = try container.decode(String.self, forKey: .name)
self.points = try container.decode(Int.self, forKey: .points)
self.isPremium = try container.decode(Bool.self, forKey: .isPremium)
}
func encode(to encoder: any Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(id, forKey: .id)
try container.encode(name, forKey: .name)
try container.encode(points, forKey: .points)
try container.encode(isPremium, forKey: .isPremium)
}
}
위에 코드를 Codable를 사용하게 된다면 아래처럼 엄청나게 간결해집니다.
struct CustomerModel: Identifiable, Codable {
let id: String
let name: String
let points: Int
let isPremium: Bool
init(id: String, name: String, points: Int, isPremium: Bool) {
self.id = id
self.name = name
self.points = points
self.isPremium = isPremium
}
}
'SwiftUI' 카테고리의 다른 글
타이머를 이용하여 아두이노 LED 켜기 (0) | 2024.04.09 |
---|---|
Timer 타이머 (0) | 2024.04.08 |
Typelias (0) | 2024.04.08 |
Weak Self (0) | 2024.04.07 |
CoreBluetooth로 아두이노 불 켜기 (1) | 2024.04.07 |