ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Swift] PromiseKit 사용하여 콜백지옥 빠져나오기
    개발/Swift 2021. 11. 30. 18:10

    아래 코드는 프로젝트(item) 를 생성 하기위해 input dialog 를 띄운후

    입력값을 받은뒤 중복 체크를 하고 유효성에따라 프로젝트를 생성하는 코드이다.

     

    @objc func onTapEdit(_ gesture : UITapGestureRecognizer){
            if let topVC = ViewManager.getTopViewController() {
                NavigationManager.showProjectCreateDialog(topVC) { (text,callBack) in
                    self.projectViewModel.checkProjectName(title: text) { isExist in
                        if(isExist){
                            callBack(.failure(CreateProjectError.existProjectNameError))
                          
                        }else{
                            self.projectViewModel.updateProject(id: self.project.id, title: text)
                            callBack(.success(true))
                        }
                    }
                }
               
            }
           
        }
    

       해당 코드는 다음 과정들을 수행한다.

    1. project create dialog 를 띄우고 유저가 지정한 프로젝트명을 받아와 콜백을 실행
    2. 존재하는 프로젝트명인지 체크후 콜백실행
    3. 존재하는 경우 ,없는경우 별도로 로직을 수행하는데 처음에 콜백 함수를 받아와서 실행

    이렇게 복잡한 로직의 경우 콜백 지옥에 빠져 가독성이 힘들어진다.  

     

    PromiseKit 사용

    리팩토링에 앞서 두 객체간의 역할을 확실히 하고자 한다.

    두객체는 다음과 같다.

    1. dialog를 띄울 ViewController (해당의 경우는 프로젝트 생성이지만 다른 곳에서도 사용가능해야함)
    2. input dialog

    위객체들의 명칭을 줄여 vc / dialog 라고 지칭한다.

    vc 의 역할은 두가지가있다.

    1. dialog에 입력된 값이 유효한지 체크하는 함수를 정의한다. (해당 경우는 중복체크)
    2. 유효한 값이라면 완료 함수를 정의한다. (해당의 경우는 프로젝트 생성)

    dialog 는 네가지 역할이있다.

    1. 입력된 text 를 받아 관리 한다.
    2. 기본적인 validation 역할을 한다 (빈값, 특수문자 오류 등...)
    3. vc에서 정의된 유효 체크를 실행한다.
    4. vc 에서 정의된 완료 함수를 실행한다.

    우선 VC의 두 역할을 정의해줬다. 위 함수는 중복체크 아래는 완료 함수이다. (중복 체크 후에 마지막에 실행할 함수)

    private func checkProjectTitleDuplicationFunction (text : String) -> Promise<Bool> {
            return Promise<Bool>{ result in
                projectViewModel.checkProjectName(title: text) { isDuplicated in
                    result.fulfill(!isDuplicated)
                }
            }
        }
        
        private func updateProject(text : String){
            self.projectViewModel.updateProject(id: self.project.id, title: text)
        }
    

    프로젝트 생성 함수는 굳이 기다리지 않아도 되기 떄문에 일반함수로 정의했고

    중복 체크 함수는 대기 후에 프로젝트를 생성하거나 에러를 던져줘야 하기 때문에 프로미스를 사용했다.

     

    @objc func onTapEdit(_ gesture : UITapGestureRecognizer){
            if let topVC = ViewManager.getTopViewController() {
                NavigationManager.showProjectCreateDialog(topVC, checkValidInput: checkProjectTitleDuplicationFunction,onClickButton:updateProject)
               
            }
           
        }
    

     

    onTapEdit() 함수가 맨처음 콜백을 사용했을때보다 훨씬 간결해 줬다.

    함수둘을 넘겨주고 함수 실행을 모두 dialog 로 보내줬기 때문이다.

    그럼 dialog 는 복잡해 졌을까?

    기존에도 dialog 에서 콜백함수를 받아와서 사용했었는데

    promise를 사용함으로 오히려 보기좋았다.

    var onClickButton : ((String)->Void)!
    var checkValidInput : ((String)->Promise<Bool>)?
    

    dialog 에서는 완료함수와 중복체크 두 함수를 전달 받았다.

    이중 중복체크같은 validcheck 함수는 옵셔널이다. 다른 usecase 에도 사용 가능해야한다.

    다른 vc에서는 중복체크를 안할수도 있기 때문이다.

    private func checkValidText(text:String) -> Promise<Bool>{
            guard let checkValidInput = self.checkValidInput else {
                return Promise{ $0.fulfill(true)}
            }
            return checkValidInput(text)
        }
    

     

    그러므로 중복 체크 함수를 전달 받지 않은 경우 그냥 true를 프로미스로 리턴해준다.

    buttonView.button.rx.tap.bind{ [weak self] in
                if let self = self ,
                   let text = self.textField.text{
                    self.checkValidText(text: text).done { checkValid in
                        if checkValid {
                            self.onClickButton(text)
                            self.dismiss(animated: false, completion: nil)
                        }else {
                            self.errorLabel.text = "CreateProjectExistError".localizedByKey()
                        }
                    }.catch{ error in
                        print(error)
                    }
                }
            }.disposed(by: disposeBag)
    

    버튼 클릭에대한 응답을 rx로 처리했다.

    checkValidText() 프로미스 함수를 실행하여 결과값을 프로미스로 전달 받았다.

     

    전달받은 결과값은 done을 통해 다음 로직을 수행시킬수 있다.

    그리고 true 인경우 onClickButton() 을 실행하여 완료 함수를 실행 시켰고

    false 인경우 에러 텍스트를 띄워 처리했다.

    댓글

Designed by Tistory.