ios 24일차

bin·2026년 1월 30일

과제에 관한 기록

15. 중첩 구조 제거( 생각1의 연장선)

  • 의문점 : 꼭 이렇게 계층형으로 객체를 생성하여 데이터를 받아야하는가?

과제를 정리하며 첫번째로 기록한 내용이다. 이를 해결하기 위해 실제로 적용한 로직을 이해하고 기록해보자
Swift의 Codable 프로토콜은 구조체 변수명과 JSON의 키가 일치하면 우리에게 보이진 않지만 자동으로 init을 생성해준다. 본인은 release_date를 releaseDate로 받아오기 위해 수동으로 선언했다. 또한, 중첩된 구조를 해결하기 위해서 수동으로 구조를 변경해볼 수 있다. 일단 Codable대신 Decodable을 채택하고 수동으로 init을 구현한다. 위 과정을 이해하고 적용하기 위해서는 컨테이너에 대한 개념을 알아야 한다. 컨테이너는 데이터가 담긴 바구니로 쉽게 말해 데이터를 포함하고 있는 범위라고 생각하면 된다.
1. CodingKeys에 우리가 사용할 최상위 키를 선언한다. (attributes)
2. decoder.container를 사용하여 한 컨테이너를 연다.
3. nestedContainer를 이용하여 실제 데이터가 담긴 컨테이터로 접근한다.
4. 접근한 데이터를 받아오자.

그렇다면 decoder.container를 두번 사용하여 컨테이너를 두번 접근하면 안되나 ?
decoder는 현재 파싱하는 데이터의 최상위를 가르킨다. 그래서 호출을 여러번 하더라도 같은 컨테이너를 지속적으로 여는 행동을 하는 것이다. 반면, nestedContainer는 현 컨테이너의 내부에 있는 다른 컨테이너에 접근할 수 있다.

struct BookResponse: Decodable {
    let data: [Book]
}

struct Book: Decodable {
    let title: String
    let author: String
    let pages: Int
    let releaseDate: Date // Date로 형식 변경 : data.json 파싱 시 String이 아니라 Date로 반환
    let summary: String
    let dedication: String
    let chapters: [Chapter]
    
    init(from decoder: any Decoder) throws {
        let attributesContainer = try decoder.container(keyedBy: CodingKeys.self)
        let bookContainer = try attributesContainer.nestedContainer(keyedBy: CodingKeys.self , forKey: .attributes)
        title = try bookContainer.decode(String.self, forKey: .title)
        author = try bookContainer.decode(String.self, forKey: .author)
        pages = try bookContainer.decode(Int.self, forKey: .pages)
        releaseDate = try bookContainer.decode(Date.self, forKey: .releaseDate)
        summary = try bookContainer.decode(String.self, forKey: .summary)
        dedication = try bookContainer.decode(String.self, forKey: .dedication)
        chapters = try bookContainer.decode([Chapter].self, forKey: .chapters)
        
    }
    
    // data.json 형식 맞추기 : releaseDate는 data.json의 release_date
    enum CodingKeys: String, CodingKey {
        case attributes
        case title, author, pages, summary, dedication, chapters
        case releaseDate = "release_date"
    }
let books = bookResponse.data

회고

UI를 다루는 첫 과제를 진행하며, 많은 생각을 하고 정보를 찾아보고 적용하며 트러블도 겪었다. 과제를 지난 주 화요일 저녁부터 시작했는데, 일찍 시작하길 잘했다고 생각한다. 사실, 바로 시작할 생각은 없었는데 팀원분들은 첫 과제를 코드베이스를 통한 UIKit으로 작업을 했었기에 내가 너무 뒤쳐지지 않을까 걱정스런 마음에 일찍 시작하게 되었다. 다른 팀원들보다 늦다고 본인을 자책하거나 실망하는 마음이 들어서 그런게 아니다, 코드 리뷰를 진행하고 팀원들과 소통을 진행하고 싶은데 작업이 늦어진다면 힘들어지지않을까라는 생각이 들었다. 예상 외로 과제는 그리 힘들지 않았다. 물론 화면 구성을 어떻게 진행해볼까, 레이아웃은 어떻게 잡을까, delegate는 언제 사용하는게 좋을까?, 상태 변화에 대한 함수는 어떻게 정의를 해야할까? ... 등 많은 어려움이 있었고, 하나하나에 대해 공부하며 진행했다. 일찍이 시작하여 요구사항과 최적화를 위해 많은 리팩토링 작업을 진행했으며, 이를 통해 알게된 내용들을 정리하며 지식을 넓힐 수 있어서 좋았다.

0개의 댓글