본문 바로가기

Swift

Custom Redux in Swift

Redux는 무엇인가요?

위 그림이요.

"예측 가능한 상태 컨테이너." 

 

한 문장으로 디자인 패턴을 표현했기 때문에,

처음 Redux를 공부하는 사람에게는 아무 도움이 되지 않는 문장일 겁니다.

위 문장을 이해하기 위해서 도움을 줄 멤버를 소개하겠습니다.

 

 

1. Action

뷰에서 특정한 장소(Store)로 이벤트를 전달할 때 사용할 멤버입니다.

아래 그림을 봤을 때 사용자 이벤트가 발생했을 때, 이를 Action이라는 열거형으로 정의하게 될 겁니다. 

뷰에서 버튼이 눌렀을 때 추가적인 작업을 할 필요 없이, 특정 Action이 발생했다고 특정한 장소(Store)로 보내기만 할 겁니다.

 

추가로사용자 이벤트뿐만 아니라 사용자 눈에 보이지 않는 이벤트들도 존재할 수 있습니다.

(가령 초기 데이터를 받거나, 다른 화면으로부터 데이터를 받아오는 경우)

 

 

2. State

State는 화면을 Action에 따라 갱신할 수 있는 상태를 말합니다.

가시적인 상태뿐만 아니라 가시적이지 않는 상태가 있을 수 있습니다.

 

 

3. Rudcer

Reducer는 해당 화면에서 발생할 이벤트를 실질적으로 처리할 객체입니다. (화면에 발생하는 모든 로직이 한곳으로 모임) 

Swift 고차함수 중에 reduce 함수를 생각하면 이해하기 쉬울 겁니다.

func reduce<Result>(
    _ initialResult: Result,
    _ nextPartialResult: (Result, Element) throws -> Result
) rethrows -> Result

 

State와 Action을 사용해서 기존 State를 변경하고 이상한 친구를 생성할 수도 있고 아닐 수도 있습니다. (Effect)

마지막 문장은 지금 이해할 필요 없이 뒷부분에서 자세히 다루겠습니다.

 

 

4. Store

Store는 위에서 소개한 멤버들을 소유하고 있는 객체입니다.

실질적으로 View로부터 Action을 전달받고 변경된 State를 전달하는 컨테이너입니다.

  1. view로부터 action을 받음
  2. reducer를 통해서 state와 action를 갖고 state를 변경
  3. 변경된 state를 view로 전달

 

 

5. Side Effect

비동기적으로 이벤트를 핸들링할 때 빠질 수 없는 존재입니다.

네트워크로부터 데이터를 받거나, 다른 화면으로부터 데이터를 받는 등 비동기적인 이벤트가 발생했을 때,

Swift는 탈출 클로저 내부에서 inout 파라미터를 변경할 수 없기 때문에, 새로운 Action(눈에 보이지 않는)를 발생해서 상태를 변경합니다.

또한 새로운 Action은 바로 발생하는 게 아닌 해당 Publisher에게 값을 받았을 때 발생하게 됩니다.

 

 


 

 

리덕스를 사용하게 되면 얻는 이점이 무언인가요?

다시 처음으로 돌아가서 Redux라는 패턴을 한 줄로 정의한 내용을 다시 보겠습니다.

"예측 가능한 상태 컨테이너."

위 문장을 아래 그림을 통해서 설명하겠습니다.

1. Predictable 

"button이 눌렸을 때 무슨 일이 발생하는지 또는 "우선 DetailView를 보여주고, 그 후에 Publisher가 값을 받게 되면 sendAnotherAction을 실행시켜줘"와 같이 Effect를 생성하고 사용함으로써, 코드의 흐름을 눈으로 볼 수 있게 되었습니다.

(예측 가능해졌다.)

 

2. Centralized

해당 뷰에서 발생하는 모든 이벤트가 reduce 메소드 내부로 모이게 됩니다.

여려 명이 작성하는 코드일 경우 엄청난 이득이라고 생각하는 부분중 하나입니다.

뷰에서 어떤 작업을 하고, viewModel로 부터 어떤 작업을 하는데 새로 추가할 기능을 어디에 추가할지 고민할 필요가 사라집니다.

모든 로직은 Reducer 내부에서 처리하게 되며, View를 꾸미는 건 State에 추가하면 됩니다. (로직을 담는 컨테이너)

 

예측이 가능하기 때문에 테스트가 가능해지며, 상태를 변화시키는 로직이 한곳으로 집결되기 때문에 신경 써야 할 코드가 줄어들게 됩니다.

 

pure function, unidirectional등 추가적인 이득이 존재하지만, 코드를 작성하면서 이득이라고 느끼지 못했기에 다른 점들은 언급하지 않았습니다.

 

ReSwift, ReactorKit, Composable Architecture 등 다른 라이브러리가 존재하는데 만들어서 사용할 필요가 있나요?

당연히 위 라이브러리를 사용하게 되면, 제공되는 추가적인 기능들과 구현 해야 할 코드가 줄어들게 될 겁니다.

해당 라이브러리를 프로젝트에 이해도 하지 않고 적용하기에는 위험부담이 크다고 생각했고, 제한된 상황에서 프로젝트에 전체적인 변경을 주지 않고, 위 라이브러리의 이점을 사용하기 위해서 작성했습니다.

 

 

예제코드

https://github.com/GangWoon/DiffableDataSource/tree/master/Refactoring/DiffableDataSource

 

 


 

 

테스트에 관해서 작성한 글입니다.

https://gangwoon.tistory.com/25

 

 

'Swift' 카테고리의 다른 글

Memory issue with closure injection  (0) 2021.08.25
Custom Redux Testable  (0) 2021.08.24
Real Time UI Test  (0) 2021.08.06