-
[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)) } } } } }
해당 코드는 다음 과정들을 수행한다.
- project create dialog 를 띄우고 유저가 지정한 프로젝트명을 받아와 콜백을 실행
- 존재하는 프로젝트명인지 체크후 콜백실행
- 존재하는 경우 ,없는경우 별도로 로직을 수행하는데 처음에 콜백 함수를 받아와서 실행
이렇게 복잡한 로직의 경우 콜백 지옥에 빠져 가독성이 힘들어진다.
PromiseKit 사용
리팩토링에 앞서 두 객체간의 역할을 확실히 하고자 한다.
두객체는 다음과 같다.
- dialog를 띄울 ViewController (해당의 경우는 프로젝트 생성이지만 다른 곳에서도 사용가능해야함)
- input dialog
위객체들의 명칭을 줄여 vc / dialog 라고 지칭한다.
vc 의 역할은 두가지가있다.
- dialog에 입력된 값이 유효한지 체크하는 함수를 정의한다. (해당 경우는 중복체크)
- 유효한 값이라면 완료 함수를 정의한다. (해당의 경우는 프로젝트 생성)
dialog 는 네가지 역할이있다.
- 입력된 text 를 받아 관리 한다.
- 기본적인 validation 역할을 한다 (빈값, 특수문자 오류 등...)
- vc에서 정의된 유효 체크를 실행한다.
- 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 인경우 에러 텍스트를 띄워 처리했다.
'개발 > Swift' 카테고리의 다른 글
[Swift] frame이 다시 초기화 되는 오류 - translatesAutoresizingMaskIntoConstraints (0) 2021.12.08 [Swift] UIResponder 대략 알아가기 (0) 2021.12.01 [Swift 코딩테스트] 프로그래머스 - 체육복 (0) 2021.11.29 GCD - DispatchQueue Main/Global 큐 스레드에 관해 (0) 2021.11.23 언제 class 대신 struct 를 사용할까? (0) 2021.11.14