안녕하세요! 미니입니다.
오늘은 TCA에서 네트워크를 처리하는 방법에 대해서 정리해보려고 합니다.
TCA를 알아보면서 사이드 이팩트에 대해서 이야기하면서 잠시 이야기 했었습니다. (안보신 분들은 TCA - 기본 에서 보시면 됩니다.) 사이드 이팩트에 대해서 잠깐 이야기 해보고 넘어가보도록 하죠!
사이드 이팩트
TCA에서 사이드 이팩트라는 용어는 어플리케이션 바깥 세상에서 일어나는 일이다. 링크
TCA 공식 문서를 바탕으로 사이드 이팩트에 대한 정의를 추론해보면 저희가 작성하고 있는 어플리케이션 바깥 세상에 대해서 이야기합니다. 즉, 네트워크를 통해서 새로운 데이터를 받아오는 작업도 사이드 이팩트가 됩니다.
직접 코드를 작성하기 전에 어떤 형식의 앱인지 소개드릴게요!
우측 네비게이션 바에 있는 버튼들은 상품의 생성과 삭제를 도와주는 친구들입니다. 본문은 상품이 존재하게 되면, 상품의 리스트를 보여주게 구성하였습니다. 해당 앱은 (https://dummyjson.com/products) 로 데이터를 받아올 수 있도록 했습니다.
네트워크 객체 구현하기
이제 직접 코드를 작성하면서 하나씩 알아보려고 합니다. 네트워크 객체를 구성하는 방법은 Combine을 통해서 구현했습니다. 실제 네트워크 통신을 구현하기 전에 디코딩할 타입을 정의해야겠죠?
1. Decoding Model
struct Products: Codable {
let items: [Product]
enum CodingKeys: String, CodingKey {
case items = "products"
}
}
struct Product: Codable, Equatable {
let id: Int
let title: String
let description: String
let price: Int
let category: String
let thumbnailPath: String
enum CodingKeys: String, CodingKey {
case id
case title
case description
case price
case category
case thumbnailPath = "thumbnail"
}
}
받아오는 데이터는 Products 라는 키로 리스트를 반환하기 때문에 데이터를 다음과 같이 정리하였습니다.
2. Network Model
실제 네트워크를 수행하는 객체를 구서해보려고 합니다. 실제 네트워크는 Combine을 통해서 Pubilsher를 생성하고, TCA의 고유 타입인 Effect 타입으로 변경하도록 구현하였습니다. 실제 네트워크와는 다르게 하드코딩이 된 부분이 있을 수 있습니다.
어떤 구조로 네트워크를 구성하였는지 아시겠나요? Effect라는 타입을 보면서 갸우뚱하게 되는 부분이 있어서 찾아왔습니다 ㅎㅎ
The Effect type encapsulates a unit of work that can be run in the outside world, and can feed data back to the Store. It is the perfect place to do side effects, such as network requests, saving/loading from disk, creating timers, interacting with dependencies, and more. Effects are returned from reducers so that the Store can perform the effects after thereducer is done running.
Effect 타입은 외부에서 실행할 수 있는 작업 단위를 캡슐화하고 데이터를 Store에 다시 공급할 수 있습니다. 네트워크 요청, 디스크에 저장 / 로딩, 타이머 생성, 의존성과의 상호작용 등과 같은 사이드 이팩트를 수행하는데 이상적입니다. Effect는 리듀서에 반환되어 리듀서가 실행을 마친 후 Store가 이팩트를 수행할 수 있게 합니다.
네 Effect라는 타입은 어플리케이션 외부에서 일어나는 일에 대한 단위를 이야기 하게 됩니다. 이는 일어난 후에 다시 리듀서에 반환되어서 리듀서가 이에 대해서 상태를 변경하거나 다른 작업을 수행시킬 수 있게 됩니다. Effect 타입은 Swift Concurrency와 Combine을 통해서 생성할 수 있게 됩니다. TCA에서 추천하는 방법은 Swift Concurrency를 활용하라고 합니다.
3. State, Action, Reducer 구성하기
이제 뷰와 연결해줄 Reducer를 구성하려고 합니다.
코드가 좀 길기는 하지만, 설명해보겠습니다. State는 실제 뷰에 보여질 상태를 저장하게 됩니다. Action은 뷰에서 발생하는 액션이나, 내부적으로 동작해야 하는 행위들에 대해서 설명하게 됩니다. 오늘 가장 중요한 타입인 Environment가 나오게 됩니다. Environment에는 저희가 구성한 네트워크 객체를 받을 수 있도록 구성하였습니다. 또한, 이벤트를 통해서 상태를 변경하고 뷰를 업데이트 해야 하기 때문에 Main Thread 객체도 함께 받았습니다.
이해가 되셨나요? Environment라는 친구는 뭐하는 친구인지 알아보아야겠죠? Environment라는 것은 의존성 관리를 위해서 필요한 환경객체 같은 겁니다. 즉, API나 디스크에 대한 접근과 같은 객체들을 활용할 수 있도록 Reducer에 주입해주는 것입니다. 하지만, 현재 TCA 버전에서는 Environment에 대한 부분이 의존성 관리 시스템을 두는 방식으로 변경되었습니다. 이 부분은 Dependencies 라이브러리에 대해서 따로 설명하도록 하겠습니다.
자, 이제 Reducer를 구성하는 친구들에 대해서 보았습니다. Reducer 내부에서는 어떤 일이 벌어지게 되는 지 알아보죠! reload 함수가 호출되게 되면, 저희는 environment 객체에서 네트워크 요청을 하게 됩니다. 결과가 반환되게 되면, catchToEffect 메서드를 통해서 Effect 내부의 Result 타입으로 변경하게 됩니다. 그 후 저희는 map 메서드를 통해서 다른 액션에게 이팩트를 전달하게 됩니다. 그 후, 결과값에 따라서 내부적으로 필요한 비즈니스 로직을 수행하면 됩니다.
4. 뷰 그리기
뷰 영역은 살짝 생략을 하겠습니다. 받아온 데이터로 편하게 이쁘게 만드시면 됩니다 ㅎㅎ 저는 store 타입을 생성해서 주입해주었습니다. 그리고, withViewStore 메서드로 viewStore 타입으로 뷰를 다시 렌더링 할 수 있도록 하였습니다.
toolbar 부분을 보시면 viewStore에 액션을 전달하여서 네트워크를 수행하도록 구성했습니다.
결론
오늘은 TCA를 학습하면서 사이드 이팩트에 대한 내용이 잘 나와있지 않아서 공유해보았습니다. 실제 네트워크를 구성하거나 어플리케이션 외부에서 일어나는 일을 컨트롤 할 수 있는 부분은 Effect라는 타입으로 수행되고, 이 타입은 Store와 Reducer로 결과를 보내주면서 실제 비즈니스 로직을 수행할 수 있습니다. 다음에는 TCA에서 Dependencies에 대해서 공부해보려고 합니다.
'IOS > SwiftUI' 카테고리의 다른 글
TCA - What is ViewStore (0) | 2023.10.08 |
---|---|
TCA 기본 (0) | 2023.09.26 |
Data Flow Through SwiftUI (0) | 2023.09.07 |