상세 컨텐츠

본문 제목

share 연산자로 Observable 재사용하기

iOS/RxSwift

by 쑤야. 2023. 4. 9. 23:24

본문

Share

share() 연산자를 사용하면 Subscribe() 할 때마다 새로운 Observable 시퀀스가 생성되지 않고, 하나의 시퀀스에서 방출되는 아이템을 공유해 사용할 수 있다


 

POME 프로젝트 RxSwift 적용을 열심히 해나가던 중..

기록 조회 API가 3번씩 호출되고 있는 것을 발견했다.

 

먼저 상황을 살펴보자면,

 

  1. POME에서 기록 조회를 할 때 페이징 조회를 사용하기 때문에, pageSubject에서 새로운 값이 방출될 때 마다 기록 조회 요청을 하고 있다.
  2. recordsResponse라는 Observable 프로퍼티가 기록 조회 응답 결과를 받는 역할을 한다.
  3. 응답을 받아오면 tableView를 reload 시키기 위해 recordsResponse를 활용해 새로운 값을 방출한다.
  4. 기록 개수에 따라 EmptyView를 보여줄지 말지 결정하기 위해 마찬가지로 recordsResponse가 방출될 때마다 연산을 진행해 hidden 여부 값을 방출한다.
func transform(_ input: Input) -> Output{

	//기록 조회
	let recordsResponse = pageSubject
	    .skip(1)
	    .do(onNext: {
	        if($0 == 0){
	            self.canRequestNextPage = false
	        }
	    }).map{ page in
	        return (page, self.filteringCondition)
	    }.flatMap{ (page, filtering) in
	        self.getRecordsUseCase.execute(goalId: self.selectedGoal.id,
	                                       requestValue: GetRecordInReviewRequestModel(firstEmotion: filtering.first,
	                                                                                   secondEmotion: filtering.second,
	                                                                                   pageable: PageableModel(page: page)))
	    }
	
	recordsResponse
	    .do(onNext: {
	        self.canRequestNextPage = !$0.last
	    }).subscribe(onNext: {
	        if($0.page == 0){
	            self.records = $0.content
	        }else{
	            self.records.append(contentsOf: $0.content)
	        }
	    }).disposed(by: disposeBag)
	
	let reloadTableView = recordsResponse
	    .map{ _ in Void() }
	    .asDriver(onErrorJustReturn: Void())
	
	let showEmptyView = recordsResponse
	    .map{ $0.page == 0 && $0.content.isEmpty }
	    .asDriver(onErrorJustReturn: false)
}

 

문제가 발생했던 코드를 동일한 상황이지만 더욱 간단하게 확인해볼 수 있도록 예시 코드를 작성해 보았다.

 

내가 의도한 상황은 아래와 같다.

 

  1. 새로 전달받은 값을 responseObservable가 받는다
  2. responseObservable를 활용해 a, b를 붙여 출력하는 등 각각의 다른 동작을 실행한다
func shareTest(){
    
    let subject = PublishSubject<Int>()
    let disposeBag = DisposeBag()
    
    let responseObservable = subject
        .do(onNext: {
            print($0)
        })
            
    responseObservable
        .subscribe(onNext: {
            print("\\($0)a")
        }).disposed(by: disposeBag)
            
    responseObservable
        .subscribe(onNext: {
            print("\\($0)b")
        }).disposed(by: disposeBag)

    subject.onNext(1)
    subject.onNext(2)
}

 

하지만 위의 함수를 실행한 결과는 아래와 같다.

1
1a
1
1b
2
2a
2
2b

responseObservable의 값을 재사용하는 것이 아니라, 아래 사진과 같이 각각 새롭게 시퀀스를 생성해 처리하고 있는 것이다.

 

 

내가 API를 호출할 때 요청이 3번씩이나 간 이유는 바로 이것 때문이었다.

 

그렇다면 이 문제를 해결하기 위해서는 어떻게 해결해야 하는가?

바로 share 연산자를 활용하는 것이다.

 

responseObservable을 구독해 각각의 기능을 구현하고 있기 때문에,

아래와 같이 responseObservable에 share을 추가해 주도록 하겠다.

let responseObservable = subject
    .do(onNext: {
        print($0)
    })
    .share()

 

나머지 부분은 모두 동일하며, 다시 함수를 실행시켜 보도록 하겠다.

1
1a
1b
2
2a
2b

 

내가 의도한 결과가 나오는 것을 확인할 수 있다.

 

@ 참고 https://jusung.github.io/shareReplay/

관련글 더보기