RxSwift에서 withLatestFrom은 방출 기준이 되는 observable이 방출될 때마다 다른 observable의 최신 값을 가져와 결합한 후, observable을 방출한다.
Combine에서 다른 publisher들을 모아서 재방출할 수 있는 연산자로 zip, merge, combineLatest 3가지가 있는데 아쉽게도 withLatestFrom와 같은 기능을 수행하는 연산자는 없다.
combineLatest가 최신 값을 가져와 방출하는 특징을 가지고 있다. 하지만 기준으로 설정한 publisher가 새로운 이벤트를 방출할 때에 대해서만 이벤트가 방출되는 것이 아니라, 기준에 상관없이 결합된 다른 publisher들이 새로운 값을 방출할 때도 새롭게 결합된 모든 이벤트를 방출하기 때문에 적합하지 않다.
만약 CTA 버튼과 텍스트 필드가 있으며, CTA 버튼의 탭 이벤트와 텍스트 필드의 텍스트 변화 값 이벤트가 combineLatest로 결합되어 있다면, CTA 버튼이 비활성화 상태일지라도 텍스트 필드의 값 변화로 인해 API가 요청되는 문제가 발생할 것이다.
진행하고 있는 프로젝트에서 withLatestFrom의 연산자가 필요했었다.
상황은 아래와 같으며, 3번 단계에서 withLatestFrom 사용을 생각했었다.
탭을 했을 때 방출되는 Publisher를 기준으로 하고, 입력값들을 withLatestFrom으로 이미 방출된 최신 값을 가져오는 로직이다. 하지만 withLatestFrom이 없으니, 다른 방법을 찾아야 했다.
publisher를 결합하여 최신 값을 끌어오는 것은 불가능하므로 publisher가 아닌, 최신 데이터 자체를 전역 변수로 관리하며 끌어와야 겠다라고 생각했다.
1. 각 입력값 마다 전역변수 프로퍼티를 선언하여 각각 관리
2. 회원가입 유스케이스 요청 모델 사용
3. View Model에서 입력값들을 관리하기 위한 구조체를 새롭게 생성
2번 방식이 재사용 측면과 효율성 측면에서 가장 적합하다고 판단했다.
2번 방식으로 프로젝트에 적용한 코드이다.
canMove.combineLatest(input.nicknameEditingEnd, input.birthdayEditingEnd, input.gender)
.sink{ [weak self] canMove, nickname, birth, gender in
if canMove {
guard let memberId = UserManager.shared.memberId else { return }
self?.signUpRequestValue = SignUpUseCaseRequestValue(
memberId: memberId,
nickname: nickname,
birth: birth,
gender: gender
)
}
else {
self?.signUpRequestValue = nil
}
}
.store(in: &cancellable)
CTA 버튼의 활성화 여부(canMove)와 회원 정보들을 결합한 Publisher를 생성했다.
회원 정보들이 변화할 때마다, signUpRequestValue는 업데이트된다.
input.moveNext
.compactMap{ [weak self] _ in
self?.signUpRequestValue
}
.flatMap{ request in
self.signUpUseCase.execute(request: request)
}
.
.
.
CTA 버튼의 탭 이벤트를 알려주는 moveNext가 방출될 때, 전역 변수로 저장하고 있었던 signUpRequestValue를 가져온다.
throttle (0) | 2024.02.29 |
---|---|
RunLoop.main과 DispatchQueue.main (0) | 2023.12.13 |
Combine과 함께 NotificationCenter 사용해보기 (0) | 2023.12.10 |