본문 바로가기
💡 Today I Learned/스터디 자료정리

[스터디11일차][RxSwift] 검색 어플 만들 때 유용한 연산자

by 솔비님 2025. 1. 20.

1.  CatchError

옵저버블에서 오류가 발생했을 때 처리하며 대체 값을 반환하거나 새로운 옵저버블로 대체한다
예를 들어, 네트워크 요청 실패할 경우 기본 데이터를 제공하거나 사용자에게 오류 메시지를 표시한다

 

< 특징 >

오류를 처리한 이후에도 스트림이 계속 동작함

대체 옵저버블이나 값을 방출할 수 있음

 

 예제 1 - 기본 값을 제공하는 CatchError 

let apiRequest = Observable<String>.create { observer in
    observer.onError(NSError(domain: "APIError", code: -1, userInfo: nil))
    return Disposables.create()
}

apiRequest
    .catchError { error in
        print("Error caught: \(error)")
        return Observable.just("Default Data") // 오류 발생 시 기본 값 반환
    }
    .subscribe(onNext: { result in
        print("Result: \(result)")
    })
// 출력:
// Error caught: APIError
// Result: Default Data

 

 예제 2 - 대체 Observable로 변환 

let primaryRequest = Observable<String>.create { observer in
    observer.onError(NSError(domain: "PrimaryError", code: -1, userInfo: nil))
    return Disposables.create()
}

let fallbackRequest = Observable.just("Fallback Data")

primaryRequest
    .catchError { _ in 
    fallbackRequest 
    } // 대체 Observable 사용
    .subscribe(onNext: { result in
        print("Result: \(result)")
    })
// 출력:
// Result: Fallback Data

 

 예제 3 - catchErrorJustReturn을 활용해서 대체 옵저버블 없이 특정한 값으로 처리 

apiRequest
    .catchErrorJustReturn("Static Fallback")
    .subscribe(onNext: { print($0) })
// 출력: Static Fallback

 

-> subscribe 가 꼭 필요한지 찾아보기

 

 

2.  Scan

옵저버블에서 방출된 값을 누적해서 상태에 저장한다
검색기록 같은 누적 데이터 이력 추적이나 상태 관리에 적합하다

 

< 특징 >

방출된 값을 계속 누적하고 누적된 값을 방출한다

초기 값을 설정할 수 있다

 

 

 예제 1 - 합계를 누적해서 계산 

let numbers = Observable.of(1, 2, 3, 4, 5)

numbers
    .scan(0) { accumulator, value in // accumulator: 누적값, value: 방출값
        return accumulator + value // 누적 계산
    }
    .subscribe(onNext: { print($0) })
// 출력:
// 1, 3, 6, 10, 15

 

 예제 2 - 검색 기록을 누적 

let searchQueries = PublishSubject<String>()

searchQueries
    .scan([]) { history, newQuery in
        return history + [newQuery] // 새로운 값을 누적
    }
    .subscribe(onNext: { history in
        print("Search History: \(history)")
    })

searchQueries.onNext("RxSwift")
searchQueries.onNext("Combine")
searchQueries.onNext("SwiftUI")
// 출력:
// Search History: ["RxSwift"]
// Search History: ["RxSwift", "Combine"]
// Search History: ["RxSwift", "Combine", "SwiftUI"]

 

 

 

3. TakeLast

옵저버블에서 마지막 n개의 방출된 값을 저장한다
스트림이 완료되기 전까지는 방출하지 않고 완료된 이후 마지막 값들을 한 번에 방출한다
검색 기록을 제한된 개수로 유지하고 싶을 때 유용하다

 

< 특징 >

마지막 n개의 값만 처리한다

반드시 스트림이 완료 된 이후에만 동작한다(onCompleted) → 무한 스트림에서는 동작하지 않는다

데이터 제한이 필요한 경우에 사용한다

 

 예제 1 - 마지막 값 가져오기 

let numbers = Observable.of(1, 2, 3, 4, 5)

numbers
    .takeLast(2) // 마지막 2개 값만 방출
    .subscribe(onNext: { print($0) })
// 출력:
// 4
// 5

 

 예제 2 - 검색 기록 제한 

let searchQueries = PublishSubject<String>()

searchQueries
    .scan([]) { history, newQuery in
        return history + [newQuery]
    }
    .map { $0.suffix(3) } // 마지막 3개의 검색 기록 유지
    .subscribe(onNext: { history in
        print("Recent Search History: \(history)")
    })

searchQueries.onNext("RxSwift")
searchQueries.onNext("Combine")
searchQueries.onNext("SwiftUI")
searchQueries.onNext("Async/Await")
// 출력:
// Recent Search History: ["RxSwift", "Combine", "SwiftUI"]
// Recent Search History: ["Combine", "SwiftUI", "Async/Await"]

 

 

 

 

Scan과 Map을 조합한 검색 기록 누적 관리

let searchText = PublishSubject<String>()

searchText
    .scan([]) { history, newQuery in
        var updatedHistory = history
        updatedHistory.append(newQuery)
        return updatedHistory
    }
    .map { history in history.suffix(5) } // 최신 5개만 유지
    .subscribe(onNext: { history in
        print("Search History: \(history)")
    })

searchText.onNext("RxSwift")
searchText.onNext("Combine")
searchText.onNext("Reactive Programming")
searchText.onNext("Functional Programming")
searchText.onNext("Concurrency")
searchText.onNext("Async/Await")
// 출력:
// Search History: ["RxSwift", "Combine", "Reactive Programming", "Functional Programming", "Concurrency"]
// Search History: ["Combine", "Reactive Programming", "Functional Programming", "Concurrency", "Async/Await"]

 

 

 

+ 이후 활용 팁들

Persistent Storage

→ scan으로 누적된 데이터를 UserDefaults나 데이터베이스에 저장하면 앱을 다시 실행해도 기록을 유지할 수 있다

 

UI 업데이트

→ bind(to:)를 사용하여 검색 기록을 테이블 뷰에 바로 반영할 수 있다