4T2F / ThinkBig

🌟씽크빅 스터디🌟
5 stars 1 forks source link

Codable 프로토콜은 무엇이며, 어떻게 사용하나요? #58

Open JooYoungNoh opened 6 months ago

JooYoungNoh commented 6 months ago
JooYoungNoh commented 6 months ago

Codable


public typealias Codable = Decodable & Encodable
//Codable은 Decodable과 Encodable로 이루어져 있다



Decodable

동작 원리

매핑 규칙

Optional 프로퍼티

디코딩 오류 처리

기본 타입 변환



Encodable

동작 원리

매핑 규칙

JSON 인코딩 옵션

디코딩과 반대 방향

예외 처리



Codable Example

Sample JSON Data

[
  {
    "id": 1,
    "title": "Grocery shopping",
    "description": "Buy milk, eggs, bread, and cheese.",
    "completed": false
  },
  {
    "id": 2,
    "title": "iOS Project",
    "description": "Work on the SwiftUI to-do list app.",
    "completed": false
  },
  {
    "id": 3,
    "title": "Read SwiftUI Documentation",
    "description": "Read the latest SwiftUI tutorials on Apple's developer website.",
    "completed": false
  },
  {
    "id": 4,
    "title": "Fitness",
    "description": "Go for a 30-minute run in the park.",
    "completed": true
  },
  {
    "id": 5,
    "title": "Book Club",
    "description": "Finish reading 'The Midnight Library' for the book club meeting.",
    "completed": true
  },
  {
    "id": 6,
    "title": "Laundry",
    "description": "Wash and fold clothes for the upcoming week.",
    "completed": false
  },
  {
    "id": 7,
    "title": "Weekly Planning",
    "description": "Plan out the work schedule for the next week, set goals and priorities.",
    "completed": false
  },
  {
    "id": 8,
    "title": "Gardening",
    "description": "Plant new flower seeds in the garden and water the plants.",
    "completed": false
  },
  {
    "id": 9,
    "title": "Learn Guitar",
    "description": "Practice guitar chords for at least 20 minutes.",
    "completed": true
  },
  {
    "id": 10,
    "title": "Call Parents",
    "description": "Have a catch-up call with mom and dad.",
    "completed": true
  }
]



Model

struct SampleModel: Codable, Equatable, Identifiable {
    var id: Int
    var title: String
    var description: String
    var completed: Bool
}



Reducer

import ComposableArchitecture

import Foundation

@Reducer
struct SampleFeature {
    @ObservableState
    struct State: Equatable {
        var toDoList: [SampleModel] = []
    }

    enum Action {
        case clickTodo(Int)
        case decodingData
        case encodingData
    }

    var body: some ReducerOf<Self> {
        Reduce { state, action in
            switch action {
            case let .clickTodo(id):
                state.toDoList[id-1].completed.toggle()
                return .none

            case .decodingData:
                guard let file = Bundle.main.url(forResource: "sample.json", withExtension: nil) else { return .none }

                do {
                    let data = try Data(contentsOf: file)

                    state.toDoList = try JSONDecoder().decode([SampleModel].self, from: data)
                } catch {
                    print("디코딩 에러")
                }
                return .none

            case .encodingData:
                do {
                    let data = try JSONEncoder().encode(state.toDoList[0])

                    let changeString = String(data: data, encoding: .utf8)

                    print(changeString ?? "")
                } catch {
                    print("인코딩 에러")
                }
                return .none
            }
        }
    }
}



View

import ComposableArchitecture

import SwiftUI

struct SampleView: View {
    let store: StoreOf<SampleFeature>

    var body: some View {
        VStack {
            HStack {
                Spacer()

                Button {
                    store.send(.encodingData)
                } label: {
                    Text("Encoding Test")
                }
            }
            .padding(.trailing)

            List(store.toDoList) { todo in
                Button {
                    store.send(.clickTodo(todo.id))
                } label: {
                    HStack {
                        VStack(alignment: .leading, spacing: 10) {
                            Text(todo.title)
                                .font(.system(size: 20, weight: .semibold))

                            Text(todo.description)
                                .font(.system(size: 15))
                        }

                        Spacer()

                        if todo.completed {
                            Image(systemName: "checkmark")
                                .resizable()
                                .frame(width: 20, height: 20)
                                .foregroundStyle(Color(uiColor: .systemBlue))
                        } else {
                            Spacer()
                                .frame(width: 20)
                        }
                    }
                }
                .foregroundStyle(.black)
            }
        }
        .onAppear {
            store.send(.decodingData)
        }
    }
}





Codable 프로토콜을 채택한 타입에서 인코딩/디코딩 키를 커스터마이징하는 방법

CodingKeys

struct SampleModel: Codable, Equatable, Identifiable {
    var id: Int
    var title1: String
    var description1: String
    var completed1: Bool

    //JSON 데이터의 키를 새로운 변수에 매핑
    enum CodingKeys: String, CodingKey {
        case id = "id"
        case title1 = "title"
        case description1 = "description"
        case completed1 = "completed"
    }
}



옵셔널

struct SampleModel: Codable, Equatable, Identifiable {
    var id: Int?
    var title: String?
    var description: String?
    var completed: Bool?
}