Starbucks Caramel Frappuccino
본문 바로가기
  • 그래 그렇게 조금씩
SwiftUI/SwiftUI(Intermediate)

16. Codable, JSON, Encodable, Decodable

by Toughie 2023. 6. 12.

⭐️Codable, JSON⭐️

Codable 프로토콜을 통해 JSON 데이터를 인코딩, 디코딩 해보자.

 

https://toughie-ios.tistory.com/113

 

JSON Parsing

JSON이란? JavaScriptObjectNotation의 약자. JSON의 문법이 자바스크립트 문법과 유사하지만 자바스크립트에서만 사용되는 것이 아니라 JSON Parsing을 지원하는 프로그래밍 언어에서는 다 사용할 수 있다.

toughie-ios.tistory.com

예전에 작성한 게시글을 한 번 훑고 시작하기.

 

- JSON은 데이터 교환을 위한 가벼운 데이터 형식

- Encoding은 특정 데이터를 JSON으로 변환

- Decoding은 JSON 데이터를 필요한 데이터 형태로 변환(보통 JSON Parsing, 파싱이라고 함)

 

데이터 모델

struct CustomerModel: Identifiable { //Encodable, Decodable, Codable
//    let id = UUID().uuidString
//보통 위와 같이 랜덤 아이디를 부여하기도 하지만, 여기서는 id를 JSON으로 받아온다고 가정
    let id: String
    let name: String
    let points: Int
    let isVIP: Bool
}

뷰 모델

final class CodableViewModel: ObservableObject {

	@Published var customer: CustomerModel?
    
    init() {
    	getData()
    }
    
    ...
    
    func getData() {
    ...
    }
    
    func getJSONData() {
    ...
    }
}

JSON ENCODING

    func getJSONData() -> Data? {
//        ENCODING용 더미 딕셔너리 
        let dictionary: [String: Any] = [
            "id": "77777",
            "name": "Toughie",
            "points": 7,
            "isVIP": true
        ]
        
        let jsonData = try? JSONSerialization.data(withJSONObject: dictionary, options: [])
        return jsonData
    }
    
만약 CustomerModel이 Encodable 프로토콜을 채택했다면? 
//        let customer = CustomerModel(id: "12345", name: "TAF", points: 9, isVIP: false)
//        let jsonData = try? JSONEncoder().encode(customer)
}

JSONSerialization 클래스의 data(withJSONObject:options:)메서드를 통해 
dictionary를 JSON 데이터로 변환. 
주어진 Dictionary를 JSOn 형식으로 *직렬화하고 이를 Data 객체로 반환.

*직렬화

객체나 데이터 구조를 일련의 바이트(byte)로 변환하는 과정.

주로 데이터를 저장하거나 전송하기 위해 사용됨.

-> 원래 형태로 복원 용이(역직렬화), 바이트로 표현되기 때문에 파일이나 네트워크 등에서 전송 및 저장 용이

 

JSON DECODING

manual decoding

    func getData() {
    //JSON 데이터를 받아와서
        guard let data = getJSONData() else { return }
        
        if
        //options -> 역직렬화 작업 세부 제어용
            let localData = try? JSONSerialization.jsonObject(with: data, options: []),
            //Any 타입을 [String: Any]로 타입캐스팅
            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 isVIP = dictionary["isVIP"] as? Bool {
			//JSON 파싱을 통한 데이터를 가지고 새로운 인스턴스 생성
            let newCustomer = CustomerModel(id: id, name: name, points: points, isVIP: isVIP)
            customer = newCustomer
        }
    }

더 간편한 디코딩 방식 

⭐️ 모델이 Decodable 프로토콜을 채택했을 경우

    func getData() {
        guard let data = getJSONData() else { return }
	    
        do {
        //JSON 데이터를 CustomModel 타입으로 변환
            self.customer = try JSONDecoder().decode(CustomerModel.self, from: data)
        } catch let error {
            print("ERROR DECODING: \(error.localizedDescription)")
        }
        //축약 ver
        //self.customer = try? JSONDecoder().decode(CustomerModel.self, from: data)
    }

 

EnCodalbe, Decodable, Codable

struct CustomerModel: Identifiable, Codable {

    let id: String
    let name: String
    let points: Int
    let isVIP: Bool
    
    //MARK: ⭐️ CODABLE 채택하면 아래 전부 자동 구현됨 ⭐️
    --------------------------------------------------------------------------------
    //인코딩, 디코딩에서 키로 사용될 수 있는 코딩키
    enum CodingKeys: String, CodingKey {
        case id
        case name
        case points
        case isVIP
    }
    //기본 생성자
    init(id: String, name: String, points: Int, isVIP: Bool) {
        self.id = id
        self.name = name
        self.points = points
        self.isVIP = isVIP
    }
    //디코딩을 통해 초기화 하는 경우
    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.isVIP = try container.decode(Bool.self, forKey: .isVIP)
    }
    //JSON 데이터로 인코딩 하는 메서드
    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(isVIP, forKey: .isVIP)
    }
}

Encodable, Decodable 프로토콜의 동작 방식과, Codable 프로토콜의 강력함을 알 수 있는 부분.

내부적으로는 저런 과정을 거치는데 Codable 프로토콜만 채택해주면 번거로운 과정을 손쉽게 넘어갈 수 있다!

'SwiftUI > SwiftUI(Intermediate)' 카테고리의 다른 글

18. Combine 컴바인 .feat JSON  (0) 2023.06.13
17. JSON Download with @escaping  (0) 2023.06.12
15. mask 마스킹  (0) 2023.05.26
14. sheet 시트 사용법 / multiple sheets  (0) 2023.05.25
13. GeometryReader / rotation3DEffect  (0) 2023.05.25