밍비
프로그램의 편린
밍비
전체 방문자
오늘
어제
  • 분류 전체보기 (64)
    • Spring (2)
    • TIL (23)
    • 프로그래머스 (12)
    • Udemy (16)
    • Typescript (2)
    • MERN (1)
    • AWS (7)

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

인기 글

태그

  • Page Moving
  • 리액트 생애주기
  • 컴포넌트트리
  • 서비스아키텍처
  • react
  • 리액트
  • Edge Locations
  • 리스트 조회
  • useState
  • DOM
  • 리액트 reducer
  • Availability Zones
  • AWS Regions
  • useParams
  • 한입 크기로 잘라먹는 리액트
  • State 합치기
  • 리액트 프로젝트 만들기
  • 데이터 수정
  • 네이버커넥트
  • overflow-wrap
  • state 끌어올리기
  • state 관리
  • useRef
  • Points of Presence
  • 함수형 update
  • useNavigate
  • 분산저장소
  • 수평 스케일링
  • API 호출
  • 한입크기로잘라먹는리액트

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
밍비

프로그램의 편린

[Swift][iOS][SwiftUI] #0801 json mock 데이터 파싱해서 화면에 뿌리기
TIL

[Swift][iOS][SwiftUI] #0801 json mock 데이터 파싱해서 화면에 뿌리기

2022. 8. 1. 17:18
728x90

위 영상을 참고해 진행했다!

실제로 서버에서 데이터를 받아오기 전, 프론트에서는 가짜데이터를 만들어서 파싱을 구현하는데, 이 때 만드는 가짜데이터를 mock 데이터라고 한다. 오늘은 이 mock데이터를 파싱해서 화면에 리스트로 뿌려보았다.

1. mock 데이터 생성하기

[
    {
        "id": 1,
        "code" : "String",
        "title": "방제",
        "type": "팀전",
        "level": 15,
        "max_participant": 2,
        "password": "mockpasswd",
        "created_user_id": ""
    },
    {
        "id": 2,
        "code" : "String",
        "title": "방제1",
        "type": "팀전",
        "level": 20,
        "max_participant": 4,
        "password": null,
        "created_user_id": ""
    },
]

먼저 이렇게 가짜데이터를 만들어준다.

2. 데이터 모델 만들기
위에서 작성한 mock 데이터를 바탕으로 데이터 모델을 만드는데, 하나하나 만드는 대신 자동으로 모델을 만들어주는 사이트를 사용했다.

Instantly parse JSON in any language | quicktype

app.quicktype.io

이렇게 json 데이터를 입력하면 자동으로 모델을 생성해준다.
Codable이라는 프로토콜을 채택했는데, 이는 Encodable과 Decodable을 합친 것으로 json 데이터의 인코딩과 디코딩을 할 수 있게 하는 프로토콜이다.
또 CodingKeys라는 enum을 볼 수 있는데, 이는 일종의 컨벤션을 위한 장치이다. json 파일에서는 snake case로 작성된 키값을 모델에서는 camel case로 쓰고 싶을 때 이를 변환시켜 쓸 수 있게 해준다.
위의 예시에서도 max_participant처럼 snake case로 작성된 키를 maxParticipant처럼 camel case로 변환시켜준 것을 볼 수 있다.

import Foundation

struct Room: Codable {
    let id: Int
    let code, title, type: String
    let level, maxParticipant: Int
    let createdUserID: String
    let password: String?
    static let allRooms: [Room] = Bundle.main.decode(file: "Rooms.json")
    static let sampleRoom: Room = allRooms[0]
    
    enum CodingKeys: String, CodingKey {
        case id, code, title, type, level
        case maxParticipant = "max_participant"
        case password
        case createdUserID = "created_user_id"
    }
}

나는 모델 이름 자체를 Room으로 하고 싶었기 때문에 이름을 고쳐주었고, 추가로 allRooms와 sampleRoom이라는 static 상수를 정의해주었다.
allRooms는 아까 만든 mock 데이터를 디코딩해서 Room struct의 배열로 만든 것이고, sampleRoom은 그 배열의 첫번째 값을 넣은 것이다.
이제 위의 방법처럼 Bundle에서 .decode로 디코딩하기 위해 Bundle의 extension을 만들 것이다.

3. Bundle extension

extension Bundle{
    func decode<T: Decodable>(file: String) -> T {
        guard let url = self.url(forResource: file, withExtension: nil) else{
                fatalError("Could not find \(file) in the project")
    }
    guard let data = try? Data(contentsOf: url) else{
        fatalError("Could not load \(file) in the project")
    }
    
    let decoder = JSONDecoder()
    
    guard let loadedData = try? decoder.decode(T.self, from: data) else{
        fatalError("Could not decode \(file) in the project")
        }
        
        return loadedData
    }
}

decode 메소드를 추가하였다. 이는 file이라는 인자로 파일이름 문자열을 받아 해당 데이터를 반환하는 지네릭 함수이다. 데이터가 어떤 형식이든 상관없이 반환시키기 위해 지네릭 함수에서 쓰는 placeholder인 T를 사용하였다.

지네릭 (Generics) - The Swift Language Guide (한국어)

Dictionary의 Key, Value와 같이 엘리먼트 간의 서로 상관관계가 있는 경우 의미가 있는 이름을 파라미터 이름으로 붙이고 그렇지 않은 경우는 T, U, V와 같은 단일 문자로 파라미터 이름을 짓습니다.

jusung.gitbook.io

지네릭 함수에 대한 자세한 설명은 위에 올린 공식문서(의 번역본,,ㅎㅎ)에서 볼 수 있다.
self.url로 해당 이름의 데이터 파일의 위치를 찾아온다.
이후 Data 구조체로 해당 url의 데이터를 동기적으로 읽어온다. 이 때문에 애플 공식문서에서는 network-based url부터 데이터를 가져올 때 이 생성자를 사용하는 것을 권장하지 않는다.

Apple Developer Documentation

developer.apple.com

그래서 나중에 실제 데이터를 받아올 때는 공식문서에서 제시하는 dataTask를 사용해보도록,,더 공부하겠다.
이렇게 데이터를 받은 후 JSONDecoder 객체를 선언해, 해당 데이터를 디코딩하고 반환시킨다!

4. 화면 구성

struct HomeView: View {
    private var rooms : [Room] = Room.allRooms
    var body: some View {
        NavigationView{
            List{
                ForEach(rooms, id: \.id){
                    room in NavigationLink(destination: DetailView(room: room)){
                        HStack(){
                            Text("\(room.title)").font(.system(size: 20))
                            Spacer()
                            VStack(){
                                Text("\(room.level)*\(room.level)")
                                Text("0/\(room.maxParticipant)")
                            }
                        }
                    }.padding(10)
                }
            }
        }
    }
}

이렇게 body var 위에 rooms라는 Room 배열에다 allRooms 스태틱 변수를 넣어 선언하고, 갖다쓴다!
(navigationLink 부분은 다른 화면으로 넘어가는 부분이라 신경쓰지 않아도 된다)

자물쇠 띄우는 부분은 글에서 생략했지만, 실행해보면 이렇게 mock 데이터가 잘 나오는 것을 확인할 수 있다.

728x90

'TIL' 카테고리의 다른 글

[WebSocket]Express 서버에 WS 합치기, 프론트와 데이터 공유하기  (0) 2022.10.09
[WebSocket] Http vs WebSocket  (0) 2022.10.07
[코틀린][안드로이드] #0721 계산기 앱 만들기 - 3  (0) 2022.07.21
#0720 [안드로이드][코틀린] 계산기 앱 만들기 - 2  (0) 2022.07.21
#0718 [안드로이드][코틀린] 계산기 앱 만들기 - 1  (0) 2022.07.20
    밍비
    밍비

    티스토리툴바