Search

RxSwift Operators #1: Creating Operators

Just

just 연산자는 단일 요소를 방출한 다음 완료되는 Observable을 생성한다. 매우 간단하고 직관적인 방식으로 단일 값을 Observable로 변환할 수 있게 해준다.
import RxSwift let observable = Observable.just("Hello, RxSwift!") observable.subscribe(onNext: { print($0) })
Swift
복사
출력 결과
Hello, RxSwift!
Swift
복사
장점
단일 요소를 방출하기에 매우 간단한 연산자임. 이를 통해 특정 값 하나를 방출해야 할 때 직관적으로 사용할 수 있음.
단일 값을 방출하고 완료한다는 명확한 목적을 가지고 있기 때문에 코드를 읽기 쉬움.
항상 동일한 값과 동일한 순서로 동작하기 때문에 예측 가능성이 높아 테스트와 디버깅에 용이함.
단점
단일 값만 방출할 수 있기 때문에 여러 값을 방출해야 하는 경우에는 다른 연산자를 사용해야 함.
고정된 값만 방출할 수 있기 때문에 동적 데이터나 조건에 따른 데이터 방출에는 적합하지 않음.

Of

of 연산자는 여러 개의 요소를 순차적으로 방출하는 연산자이다. 주로 짧은 시퀀스를 테스트하거나 특정 값들을 한 번에 방출해야 할 때 유용하다.
import RxSwift let disposeBag = DisposeBag() let observable = Observable.of(1, 2, 3, 4, 5) observable.subscribe { event in switch event { case .next(let value): print("Next: \(value)") case .error(let error): print("Error: \(error)") case .completed: print("Completed") } }.disposed(by: disposeBag)
Swift
복사
출력 결과
Next: 1 Next: 2 Next: 3 Next: 4 Next: 5 Completed
Swift
복사
위 코드는 1, 2, 3, 4, 5라는 정수 시퀀스를 방출하는 Observable을 생성하고 이를 구독하여 각 요소를 출력한다. 마지막으로 시퀀스가 완료되면 Completed 메시지를 출력한다.
장점
코드가 간단하고 직관적임.
단위 테스트를 할 때 짧은 시퀀스를 쉽게 생성할 수 있어 테스트에 용이함.
단점
긴 시퀀스를 다룰 때는 코드가 길어질 수 있음.
of 연산자도 정적 데이터에 적합하며 동적으로 변하는 데이터를 처리하기에는 적합하지 않음.

From

from 연산자는 시퀀스 또는 배열과 같은 컬렉션을 Observable 시퀀스로 변환하는 데 사용된다. 이를 통해 컬렉션의 각 요소를 차례로 방출하는 Observable을 생성할 수 있다. 간단히 말해, 컬렉션을 Observable로 바꾸어 각 요소를 순차적으로 처리할 수 있게 해준다.
import RxSwift let disposeBag = DisposeBag() let numbers = [1, 2, 3, 4, 5] Observable.from(numbers) .subscribe(onNext: { number in print(number) }) .disposed(by: disposeBag)
Swift
복사
출력 결과
1 2 3 4 5
Swift
복사
장점
시퀀스나 배열과 같은 컬렉션을 Observable로 쉽게 변환할 수 있음. 이를 통해 반응형 프로그래밍을 더욱 손쉽게 도입할 수 있음.
컬렉션의 각 요소를 개별적으로 처리할 수 있어 필요한 경우 각 요소에 대해 별도의 처리를 적용할 수 있음.
단점
큰 컬렉션을 처리할 때는 모든 요소를 개별적으로 방출하기 때문에 성능에 문제가 발생할 수 있음. 따라서 컬렉션의 크기가 매우 큰 경우에는 주의가 필요함.
컬렉션의 모든 요소를 방출하기 전까지 에러를 발생시키지 않음. 즉, 컬렉션의 모든 요소가 Observable로 변환된 후에야 에러가 발생할 수 있으므로 에러 처리가 다소 복잡해질 수 있음.

Range

range 연산자는 시작 값과 길이를 받아서 해당 범위의 정수를 순차적으로 방출하는 Observable을 생성한다. 이 연산자는 특히 일정 범위의 정수 값을 순회하거나 반복적인 작업을 수행할 때 유용하게 사용될 수 있다.
import RxSwift let disposeBag = DisposeBag() Observable.range(start: 1, count: 5) .subscribe(onNext: { value in print("Value: \(value)") }) .disposed(by: disposeBag)
Swift
복사
이 코드는 1부터 시작하여 5개의 연속된 정수를 방출하는 Observable을 생성한다.
출력 결과
Value: 1 Value: 2 Value: 3 Value: 4 Value: 5
Swift
복사
장점
특정 범위의 정수를 방출하기에 간단하고 직관적임.
간결한 코드로 반복 작업을 수행할 수 있어 코드의 가독성과 유지보수성을 높임.
반복적인 작업을 수행할 때 유용하며 테스트 데이터 생성 등에서도 사용할 수 있음.
단점
시작 값과 길이가 고정되어 있어 동적으로 범위를 조정해야 하는 경우에는 유연성이 떨어질 수 있음.
오직 정수 범위에 대해서만 동작하므로 다른 타입의 시퀀스를 생성하는 데에는 사용할 수 없음.
큰 범위의 정수를 생성할 경우 메모리 사용량이 증가할 수 있음.

Generate

generate 연산자는 특정 조건을 만족할 때까지 값을 생성하는 연산자이다.
import RxSwift let disposeBag = DisposeBag() Observable.generate( initialState: 1, condition: { $0 <= 10 }, iterate: { $0 + 1 } ) .subscribe(onNext: { print($0) }) .disposed(by: disposeBag)
Swift
복사
초기 상태는 1이고 조건은 상태가 10 이하인 동안이며 현재 상태에서 1을 더한 값을 반환하도록 하였다. 이 코드는 1부터 시작하여 10까지의 숫자를 차례로 출력하는 코드이다.
출력 결과
1 2 3 4 5 6 7 8 9 10
Swift
복사
장점
초기 상태, 조건, 다음 상태를 자유롭게 정의할 수 있어 다양한 시퀀스를 쉽게 생성할 수 있음.
코드가 명확하고 읽기 쉬우며 어떤 조건으로 시퀀스가 생성되는지 쉽게 이해할 수 있음.
조건이 만족될 때까지 시퀀스를 지연 평가하여 필요한 값만 생성함.
단점
조건이 잘못 설정되면 무한 루프에 빠질 수 있어 주의가 필요함.
복잡한 조건이나 상태 업데이트 로직을 사용할 경우 가독성이 떨어질 수 있음.

Repeat Element

repeatElement 연산자는 지정된 요소를 반복적으로 방출하는 Observable을 생성한다. 무한히 반복되므로 적절하게 사용하기 위해 take 제어 연산자와 결합하여 사용해야 한다.
import RxSwift let disposeBag = DisposeBag() Observable.repeatElement("Hello, RxSwift!") .take(5) // 5번만 방출하도록 제어 .subscribe(onNext: { value in print(value) }) .disposed(by: disposeBag)
Swift
복사
출력 결과
Hello, RxSwift! Hello, RxSwift! Hello, RxSwift! Hello, RxSwift! Hello, RxSwift!
Swift
복사
장점
특정 요소를 반복적으로 방출하는 단순한 방법을 제공함.
take, filter, map 등 다른 연산자와 결합하여 다양한 용도로 활용할 수 있음.
반복되는 값이 예측 가능하여 테스트와 시뮬레이션에 적합함.
단점
무한히 반복되므로 제어하지 않으면 메모리 및 성능 문제가 발생할 수 있음. 반드시 takedispose와 함께 사용해야 함.
하나의 요소만 반복되므로 다양한 요소를 방출하는 시퀀스를 생성하기 위해서는 추가적인 작업이 필요함.
반복적인 요소 방출이 필요한 경우에만 유용하며 대부분의 실제 응용 프로그램에서는 제한적으로 사용됨.

Deferred

deferred 연산자는 Observable 생성 과정을 지연시키고 구독자가 있을 때마다 새로운 Observable을 생성한다. 즉, 각 구독자가 연결될 때마다 Observable을 재생성하여 구독자가 Observable의 상태에 영향을 미치지 않도록 보장한다.
import RxSwift // Deferred Observable 생성 let deferredObservable: Observable<Int> = Observable.deferred { // 새로운 Observable 생성 let randomInt = Int.random(in: 1...100) return Observable.just(randomInt) } // 첫 번째 구독 deferredObservable.subscribe(onNext: { value in print("첫 번째 구독: \(value)") }).disposed(by: DisposeBag()) // 두 번째 구독 deferredObservable.subscribe(onNext: { value in print("두 번째 구독: \(value)") }).disposed(by: DisposeBag())
Swift
복사
deferredObservable은 구독할 때마다 새로운 Observable을 생성한다. 각 구독은 별도의 randomInt 값을 생성하고 각 구독자가 고유한 값을 받게 된다.
출력 결과
첫 번째 구독: 43 두 번째 구독: 74
Swift
복사
장점
deferred 연산자는 각 구독자가 독립적인 상태를 가지도록 보장함. 이를 통해 다른 구독자의 상태 변화에 영향을 받지 않게 됨.
Observable의 생성을 필요할 때까지 지연시킬 수 있어 불필요한 연산을 줄일 수 있음.
구독 시점에 동적으로 값을 생성할 수 있어 더 유연한 Observable을 만들 수 있음.
단점
각 구독마다 새로운 Observable을 생성하기 때문에 생성 비용이 높아질 수 있음.
deferred 연산자를 사용하여 Observable을 동적으로 생성할 경우, 코드의 복잡성이 증가할 수 있음.

Create

create 연산자는 RxSwift에서 사용자 정의 Observable을 생성할 수 있게 해주는 연산자이다. 개발자가 직접 이벤트를 생성하고 이를 제어할 수 있도록 해준다. 이를 통해, 비동기 작업이나 콜백 기반의 API를 RxSwift의 스트림으로 변환할 수 있다.
import RxSwift // DisposeBag 생성 let disposeBag = DisposeBag() // create 연산자를 사용하여 Observable 생성 let myObservable = Observable<String>.create { observer in // Observer에게 next 이벤트 전송 observer.onNext("Hello") observer.onNext("RxSwift!") // Observer에게 completed 이벤트 전송 observer.onCompleted() // Disposable 리턴 return Disposables.create() } // Observable 구독 myObservable.subscribe( onNext: { value in print("Value: \(value)") }, onCompleted: { print("Completed") } ).disposed(by: disposeBag)
Swift
복사
출력 결과
Value: Hello Value: RxSwift! Completed
Swift
복사
장점
개발자가 원하는 대로 이벤트를 정의하고 전송할 수 있기 때문에 매우 유연함. 이를 통해 복잡한 비동기 작업을 쉽게 Observable로 변환할 수 있음.
이벤트의 순서와 타이밍을 개발자가 직접 제어할 수 있으므로 이벤트 생성 과정을 세밀하게 관리할 수 있음.
콜백 기반의 API를 RxSwift의 Observable로 변환할 때 유용함.
단점
리소스 관리에 주의하지 않으면 메모리 누수가 발생할 수 있음. 특히, 비동기 작업을 처리할 때 주의해야 함.
이벤트 생성과 스트림 제어를 모두 수동으로 처리해야 하기 때문에 코드가 길어지고 관리가 어려워질 수 있음.
에러 처리하는 것이 다른 연산자에 비해 복잡할 수 있음.

Empty

empty 연산자는 어떠한 항목도 방출하지 않고 완료 이벤트만 방출하는 Observable을 생성한다. 즉, 구독자가 구독을 하더라도 아무런 데이터도 받지 못하고 바로 완료된다. 이는 특정 상황에서 매우 유용하게 사용될 수 있다. 예를 들어, 조건문에 따라 Observable을 선택해야 하는 상황에서 조건을 만족하지 않을 때 빈 Observable을 반환할 수 있다.
import RxSwift let disposeBag = DisposeBag() Observable<Int>.empty() .subscribe( onNext: { value in print("Value: \(value)") }, onCompleted: { print("Completed") } ) .disposed(by: disposeBag)
Swift
복사
출력 결과
Completed
Swift
복사
장점
단순성
명확성
불필요한 상태 관리나 데이터 방출을 방지할 수 있음.
단점
잘못 사용하면 의도치 않은 동작을 유발할 수 있음. 예를 들어, 실제로 데이터가 필요한 상황에서 빈 Observable을 반환하면 버그를 초래함.
단순히 완료 이벤트만 방출하기 때문에 복잡한 로직에는 적합하지 않을 수 있음.

Error

error 연산자는 Observable 시퀀스가 에러를 방출하고 종료할 수 있도록 하는 연산자이다. 이는 Observable이 어떤 에러 상황을 만났을 때 해당 에러를 구독자에게 전달하고 스트림을 종료하도록 한다.
import RxSwift // 에러 타입 정의 enum MyError: Error { case anError } // DisposeBag 생성 let disposeBag = DisposeBag() // Observable 시퀀스 생성 let observable = Observable<Int>.create { observer in observer.onNext(1) observer.onNext(2) observer.onError(MyError.anError) observer.onNext(3) // 이 이벤트는 방출되지 않음 observer.onCompleted() return Disposables.create() } // 구독 observable.subscribe( onNext: { value in print("Next:", value) }, onError: { error in print("Error:", error) }, onCompleted: { print("Completed") } ).disposed(by: disposeBag)
Swift
복사
출력 결과
Next: 1 Next: 2 Error: anError
Swift
복사
장점
스트림에서 발생하는 에러를 명확하게 처리할 수 있도록 함. 코드의 가독성을 높이고 유지보수성을 높임.
스트림을 명확하게 종료함으로써 불필요한 리소스 소비를 방지하고 메모리 누수를 예방하는 데 도움을 줌.
스트림 내에서 에러가 발생하는 지점을 명확히 할 수 있으므로 디버깅이 용이함.
단점
에러가 발생하면 스트림이 종료되므로 이후의 이벤트를 받을 수 없음. 이는 스트림이 지속적으로 동작해야 하는 경우, 문제가 될 수 잇음.
에러 발생 후 스트림을 복구하거나 재시작하려면 추가적인 코드가 필요함. 예를 들어, catchErrorretry 연산자를 사용하여 에러를 처리하고 스트림을 재시작해야 함.