[애니또] ViewController와 View의 분리 - 리팩토링 (1)

앞전에 작성한 글을 보면, UIViewController에서 View를 분리한 과정을 볼 수 있다. Delegate 패턴을 통해 데이터와 액션을 주고 받았다.

DetailWaitView를 MVC패턴에서 MVVM으로 변경하는 과정 중 먼저 한 작업은 네트워크 통신을 통해 방 정보를 불러와서 View에 바인딩하는 작업이었다.

기존의 방식과 크게 달라진 부분은 없지만, 핵심은 Publisher를 사용한 Stream으로 만들었다는 것이다.

이해를 돕기위해 기존 MVC 코드부터 살펴보자.

// 기존 코드

final class DetailWaitViewController: BaseViewController {

    private var roomInformation: Room?

    override func viewDidLoad() {
        super.viewDidLoad()
        self.fetchRoomData()
				// 생략
    }

    // MARK: func

    private func fetchRoomData() {
        self.requestWaitRoomInfo() { [weak self] result in
            switch result {
            case .success(let room):
                DispatchQueue.main.async {
                    self?.detailWaitView.updateDetailWaitView(room: room)
                }
            case .failure:
                self?.makeAlert(title: TextLiteral.errorAlertTitle,
                                message: TextLiteral.detailWaitViewControllerLoadDataMessage)
            }
        }
    }

    // MARK: network

    private func requestWaitRoomInfo(completionHandler: @escaping ((Result<Room, NetworkError>) -> Void)) {
        Task {
            do {
                let data = try await self.detailWaitService.getWaitingRoomInfo(roomId: self.roomIndex.description)
                if let roomInfo = data {
                    self.roomInformation = roomInfo
                    completionHandler(.success(roomInfo))
                }
            } catch NetworkError.serverError {
                completionHandler(.failure(.serverError))
            } catch NetworkError.clientError(let message) {
                completionHandler(.failure(.clientError(message: message)))
            }
        }
    }
}

간단하게 핵심은 총 3개다.

  1. ViewDidLoad단계에서 fetchRoomData 함수 실행
  2. Completion Handler를 통해 불러온 방 정보를 view에 업데이트
  3. roomInformation 변수에 데이터 할당

위 코드를 보면 ViewDidLoad 단계에서 fetchRoomData() 함수를 실행하고, 불러온 room 데이터를 self?.detailWaitView.updateDetailWaitView(room: room) 해당 뷰에 업데이트 시킨다.

그리고 방 정보를 self.roomInformation = roomInfo 변수에 저장한다. 해당 방 정보를 변수에 저장하는 이유는 초대코드를 복사하는 버튼을 눌렀을 때, 초대코드를 네트워크 통신을 통해 받아오는 것이 아니라 이미 받아왔던 데이터에서 초대 코드를 사용해 복사한다.

guard let invitationCode = self.roomInformation?.invitation?.code else { return }

이 코드 때문에 네트워크 통신으로 받아온 방 정보를 변수에 저장하고 있다.

위의 flow가 기존의 방 정보를 불러와서 View에 연결하는 코드였다.

그렇다면 이젠 MVVM으로 어떻게 변경했을까?

우선 DetailWaitViewModel을 만들었다.