Codable, Decodable, and Encodable in Swift | Continued Learning #21
// struct CustomerModel: Identifiable, Decodable, Encodable {
// ...
// }
struct CustomerModel: Identifiable, Codable {
...
}
func getDataDecoder() {
guard let data = getJSONData2() else { return }
do {
self.customer = try JSONDecoder().decode(CustomerModel.self, from: data)
} catch {
print(error.localizedDescription)
}
}
import SwiftUI
// DOWNLOAD DATA FROM NETWORK AS JSON
// JSON CONVERT -> DATA WE USE
struct CustomerModel: Identifiable, Decodable, Encodable {
let id: String
let name: String
let points: Int
let isPremium: Bool
enum CodingKeys: String, CodingKey {
case id
case name
case points
case isPremium
}
init(id: String, name: String, points: Int, isPremium: Bool) {
self.id = id
self.name = name
self.points = points
self.isPremium = isPremium
}
// DECODABLE
init(from decoder: 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)
}
// 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(points, forKey: .points)
try container.encode(isPremium, forKey: .isPremium)
}
}
class CodableViewModel: ObservableObject {
@Published var customer: CustomerModel? = nil
init() {
getDataDecoder()
}
func getDataDictionary() {
guard let data = getJSONData() else { return }
let jsonString = String(data: data, encoding: .utf8)
print(jsonString)
// Optional("{\"isPremium\":true,\"name\":\"Henry\",\"id\":\"12345\",\"points\":5}")
if
let localData = try? JSONSerialization.jsonObject(with: data),
let dictionary = localData as? [String:Any],
let id = dictionary["id"] as? String,
let name = dictionary["name"] as? String,
let points = dictionary["points"] as? Int,
let isPremium = dictionary["isPremium"] as? Bool {
let newCustomer = CustomerModel(id: id, name: name, points: points, isPremium: isPremium)
customer = newCustomer
}
// getData as Dictionary
}
func getDataDecoder() {
guard let data = getJSONData2() else { return }
do {
self.customer = try JSONDecoder().decode(CustomerModel.self, from: data)
} catch {
print(error.localizedDescription)
}
}
func getJSONData() -> Data? {
// DOWNLOAD FROM NETWORK
// ASNYC -> ESCAPING CLOSURE OR AWAIT, ETC.
let dictionary: [String:Any] = [
"id" : "12345",
"name" : "Henry",
"points" : 5,
"isPremium" : true,
]
do {
let jsonData = try JSONSerialization.data(withJSONObject: dictionary)
return jsonData
} catch {
print(error.localizedDescription)
}
return nil
}
func getJSONData2() -> Data? {
let customer = CustomerModel(id: "111", name: "Amy", points: 30, isPremium: false)
let jsonData = try? JSONEncoder().encode(customer)
return jsonData
}
}
struct CodableBootCamp: View {
@StateObject private var viewModel = CodableViewModel()
var body: some View {
VStack(spacing: 20) {
if let customer = viewModel.customer {
Text(customer.id)
Text(customer.name)
Text("\(customer.points)")
Text(customer.isPremium.description)
}
}
}
}
Encodable
, Decodable
을 사용하지 않고 JSON 데이터 읽고 쓰기: [String:Any]
로 JSON 만들기 → JSON 오브젝트를 [String:Any]
딕셔너리로 캐스팅 → 프로퍼티 가져와서 새로운 구조체 이니셜라이즈Decodable
사용: 기존 구조체 생성자 이외에 Decodable
을 사용하는 생성자 선언. 구조체의 프로퍼티를 코딩 키로 사용하는 컨테이너 구현 → JSON 디코더 사용Encodable
사용: 구조체 함수 encode
(Encodable
프로토콜을 준수하는 함수)에 코딩 키에 대한 구조체 프로퍼티 넣기 → JSON 인코더 사용Codable
사용: Encodable
, Decodable
모두 사용, 코딩 키와 함께 Decodable
위한 생성자 및 encdoe
함수 모두 자동으로 생성(커스텀 가능).