
rxoptional을 추가하여 사용 가능.viewWillAppear, viewWillDisappear 등의 이벤트를 Observable로 변환.take 1 연산자 사용.rx.bounds, rx.center 등의 UIKit 확장 기능을 통해 UI 요소의 변화 감지.rxnavigate, rxdatasource, rxpromise 등 다양한 라이브러리 포함.tabgesture, when, recognized 메서드를 통해 제스처 인식 및 처리.import UIKit
import RxSwift
import RxCocoa
import RxRelay
let os1 = Observable.just("Hi there!")
// 데이터를 방출 하는 observable 입니다.
let sub1 = os1.subscribe(onNext: {
// 그리고 그 observable을 구독 하는 구독 객체 입니다.
event in
print(event)
},onError: {
print($0)
}, onCompleted: {
print("completed")
}, onDisposed: {
print("disposed")
})
let disoseBag = DisposeBag()
sub1.disposed(by: disposeBag)
// 결과 값들 입니다.
// Hi there!
// completed
// disposed
let os2 = Observable.from([1,2,3])
// 데이터를 방출 하는 observable 입니다.
let sub2 = os2.subscribe(onNext: {
print($0)
}).disposed(by: disposeBag)
// observable을 구독 하는 객체 입니다.
// 순서대로 1, 2, 3 을 방출 합니다.
Observable.of("apple", "pears", "banana")
.subscribe(onNext: {
print($0)
})
.disposed(by: disposeBag)
// apple
// pears
// banana

PublishSubject와 유사하게 동작하지만, 종료되거나 오류를 방출할 수 없습니다.BehaviorSubject와 유사하게 동작하지만, 종료되거나 오류를 방출할 수 없습니다.asObservable 메서드를 사용하여 트레잇을 일반 Observable로 변환할 수 있습니다.asSingle(), asCompletable(), asMaybe() 등의 메서드를 사용하여 Observable을 해당 트레잇 형태로 변환할 수 있습니다.Single은 이름에서 알 수 있듯이 단 하나의 값을 방출하거나 오류를 방출합니다.Single은 정확히 하나의 결과만을 방출하거나 오류를 방출합니다.Single과 Completable의 중간 형태로, 하나의 요소를 방출하거나 방출 없이 완료/오류 이벤트만을 방출하고 싶을 때 사용합니다.Driver와 유사하지만, 새로운 구독자에게 마지막 이벤트를 재생하지 않습니다.let os1 = observable.just("e1")
// 하나의 observable을 생성 합니다.
// just는 단일이기 때문에 하나의 스트림만 생성 합니다.
let disB = DisposeBag()
// 메모리 해제를 위해서 disB 변수를 생성 합니다.
ob1.asSingle()
.subscribe(onSuccess: {
print($0)
}.onError: {
print($0)
})
.disposed(by: disB)
// e1
let os1 = observable.just("e1", "e2")
Completable.empty()
// RX의 특별한 observable 중 하나 입니다.
// 값을 방출 하지 않고 성공적으로 완료 되었는지만 알려줍니다.
.subscribe(onCompleted: {
print("completed")
}, onError: {
print($0)
})
// completed
let os2 = Observable.of("e2")
// 단일 값을 방출 하는 Observable을 생성 합니다.
os2.asMaybe()
// asMaybe() 메서드는 Observable을 Maybe라는 특별한 타입의 Observable로 변환합니다.
.subscribe(onSuccess: {
print($0)
}, onError: {
print($0)
}, onCompleted: {
print("complete")
// Maybe가 성공적으로 완료됐을 때 실행됩니다. 여기서는 "complete"라는 문자열을 출력합니다.
})
// e2
let os2 = Observable<Any>.empty()
// 아무런 값을 방출하지 않고 즉시 완료 되는 Observable입니다.
// 아무런 값이 없기 때문에 어느 요소도 출력 되지 않고, 에러도 나지 않기 때문에 complete가 출력 됩니다.
// complete
let os3 = Observable.of("e3", "e4")
// "e3"와 "e4" 두 개의 값을 순서대로 방출하는 Observable을 생성합니다.
os3.asDriver(onErrorJustReturn: "default")
// asDriver 메서드는 Observable을 Driver라는 특별한 타입의 Observable로 변환합니다.
// Driver는 항상 메인 스레드에서 동작하며 오류를 방출하지 않습니다. 오류가 발생하면 제공된 기본 값("default")을 대신 방출합니다.
.drive(onNext: {
print($0)
}, onCompleted: {
print("drive complete")
}, onDisposed: {
print("driver disposed")
})
.disposed(by: dispB)
// e3
// e4
// drive complete
// driver disposed
RxMarbles: Interactive diagrams of Rx Observables
Observable.of(8, 12, 9, 11)
.filter { $0 > 10 }
.subscribe(onNext: { print($0) })
// 출력: 12, 11Observable.of(1, 2, 3, 4)
.skip(2)
.subscribe(onNext: { print($0) })
// 출력: 3, 4Observable.of(8, 9, 12, 11)
.takeWhile { $0 < 12 }
.subscribe(onNext: { print($0) })
// 출력: 8, 9Observable.of(1, 2, 3)
.map { $0 * 2 }
.subscribe(onNext: { print($0) })
// 출력: 2, 4, 6Observable.of(1, 2, 3)
.flatMap { Observable.of($0, $0*10) }
.subscribe(onNext: { print($0) })
// 출력: 1, 10, 2, 20, 3, 30Observable.of(2, 3, 4)
.startWith(1)
.subscribe(onNext: { print($0) })
// 출력: 1, 2, 3, 4let first = Observable.of(1, 2)
let second = Observable.of(3, 4)
first.concat(second)
.subscribe(onNext: { print($0) })
// 출력: 1, 2, 3, 4let first = Observable.of(1, 3)
let second = Observable.of(2, 4)
Observable.merge(first, second)
.subscribe(onNext: { print($0) })
// 출력: 1, 3, 2, 4 (순서는 예시일 뿐, 실제로는 어떤 Observable이 먼저 값을 방출하는지에 따라 다를 수 있습니다.)let first = Observable.of(1, 2)
let second = Observable.of(3, 4)
Observable
.combineLatest(first, second) { $0 + $1 }
.subscribe(onNext: { print($0) })
// 출력: 4, 6filter와 skiplet disB = DisposeBag()
// 메모리 관리를 위해서 DisposeBag을 우선 생성 합니다.
// 구독이 끝나면 자동으로 메모리를 해제 할 수 있습니다.
let os1 = Observable.of("a1", "b1", "a2")
// observable을 통해서 데이터를 생성 합니다.
os1.filter({
// 연산자를 이용해서 observable의 데이터 속에서 사용할 데이터를 골라냅니다.
elem in
elem.starts(with: "a")
// a로 시작 하는 요소만 선택 합니다.
})
.subscribe(onNext: {
print($0)
// subscribe를 통해 os1을 구독 하고 그 결과를 print 합니다.
})
.disposed(by: dispB)
os1.skip(2)
// observable에서 처음 두개의 요소는 건너 뜁니다.
.subscribe(onNext: {
print($0)
// 그러면 "a2"만 남게 됩니다. 그리고 그 결과를 출력 합니다.
})
.disposed(by: dispB)
// a1
// a2
// a2
os1.elementAt(1)
skip을 elementAt(1)로 변경 하면 1번의 요소를 선택 하게 되는 것이기 때문에 “b1”이 출력 됩니다. 컴퓨터는 0,1,2의 순서로 세기 때문입니다.flatMap과 flatMapLatestos1.flatMap({
// os1 Observable에서 각 요소(elem)에 대해 flatMap이 호출됩니다.
elem in
return Observable.of("c", "d")
// flatMap 내부에서 새로운 Observable을 생성합니다: Observable.of("c", "d").
.map({
value in
"" + elem + value
// 새로운 Observable의 각 요소(value)는 map 연산자를 사용하여 변환됩니다.
// 변환은 elem과 value를 결합하는 것으로 이루어집니다.
// os1의 첫 번째 요소 "a1"에 대해 "a1c"와 "a1d"가 방출됩니다.
// os1의 두 번째 요소 "b1"에 대해 "b1c"와 "b1d"가 방출됩니다.
// os1의 세 번째 요소 "a2"에 대해 "a2c"와 "a2d"가 방출됩니다.
})
})
.disposed(by: dispB)
flatMap:
flatMap은 원본 Observable에서 방출되는 모든 요소에 대해 새로운 Observable을 생성하고, 이 새로운 Observable에서 방출되는 모든 요소를 결과 Observable로 병합합니다.os1.flatMapLatest({
flatMapLatest:
flatMapLatest는 원본 Observable에서 방출되는 각 요소에 대해 새로운 Observable을 생성하는 것은 flatMap과 동일합니다.flatMapLatest를 사용할 수 있습니다.zipObservable.zip(os1, os2)
.subscribe(onNext: {
print($0)
})
.disposed(by: dispB)
// ("a1", 1)
// ("b1", 2)
// ("a2", 3)
zip:
zip은 두 개 이상의 Observable을 "짝지어" 방출합니다.zip은 그 요소들을 짝지어서 튜플로 묶어 결과 Observable로 방출합니다.ObservableA가 [1, 2, 3]을 방출하고 ObservableB가 [A, B]를 방출한다면, 결과는 [(1, A), (2, B)]가 됩니다. 3은 짝지어지지 않았기 때문에 결과에 포함되지 않습니다.zip은 여러 Observable의 방출을 짝지어서 튜플로 묶어 결과 Observable로 방출합니다.mergeObservable.merge(os1, Observable.of("c","d")
merge는 두 개 이상의 Observable의 방출을 하나의 Observable로 합칩니다.ObservableA가 1 -> 2 -> 3 순서로 방출하고, ObservableB가 A -> B 순서로 방출한다면, 결과 Observable의 가능한 방출 순서는 1 -> A -> 2 -> B -> 3 또는 1 -> 2 -> A -> 3 -> B 등 다양하게 될 수 있습니다.merge는 여러 Observable의 방출을 그대로 합쳐 결과 Observable로 방출합니다.scan
let os2 = Observable.of(1,2,3,4)
os2.scan(Int()) {
// scan 연산자는 Observable의 각 요소에 대해 누적 연산을 수행하는 연산자입니다.
// scan 연산자는 초기값(Int(), 즉 0)과 함께 제공된 클로저를 사용하여 Observable에서 방출되는 각 요소에 대한 누적된 결과를 생성합니다.
// 클로저의 첫 번째 인자는 누적값(sum)이고, 두 번째 인자는 Observable에서 방출된 현재의 요소(elem)입니다.
sum, elem in
// 첫 번째 인자는 sum 이고 두번째 인자는 elem 입니다.
// 그리고 sum과 elem을 계속 누적 하면서 결과를 리턴 합니다.
return sum + elem
}
.subscribe(onNext: {
print($0)
// 첫 번째 요소 1이 scan에 전달되면, 0(초기값) + 1 = 1이 출력됩니다.
// 두 번째 요소 2가 scan에 전달되면, 1(이전의 누적값) + 2 = 3이 출력됩니다.
// 세 번째 요소 3이 scan에 전달되면, 3(이전의 누적값) + 3 = 6이 출력됩니다.
// 네 번째 요소 4가 scan에 전달되면, 6(이전의 누적값) + 4 = 10이 출력됩니다.
})
.disposed(by: dispB)
onError: 구독 시 오류 처리 방법.do(onError:): 오류를 부수 효과로 개별적으로 처리.catch: 오류 복구 지정.retry: 오류 발생 시 작업을 다시 시도let observable = Observable.of("a", "b", "c")
// Observable.of는 주어진 인수들로부터 Observable을 생성합니다.
// 따라서 이 Observable은 순차적으로 "a", "b", "c" 값을 방출합니다.
.map { value -> String in
// map 연산자는 Observable이 방출하는 각 요소에 대해 적용되는 함수를 통해 이 요소들을 변환합니다.
// 여기서는 "b"라는 값이 나오면 SomeError()라는 오류를 발생시킵니다. 그렇지 않으면 그대로 값을 반환합니다.
if value == "b" {
throw SomeError()
}
return value
}
observable
.catchError { error in
return Observable.just("d")
// catchError 연산자는 Observable에서 오류가 발생할 경우 이를 처리하도록 도와줍니다.
// 이 경우, 오류가 발생하면 새로운 Observable을 반환하여 "d"라는 값을 방출합니다.
}
.subscribe(onNext: { print($0) })
// .subscribe를 사용하여 Observable을 구독하고, Observable이 방출하는 각 값을 출력합니다.
// 결과적으로, 이 코드는 "a", "d", "c"를 순서대로 출력합니다.
// "b" 대신 "d"가 출력되는 이유는 "b"에서 오류가 발생하고 catchError에 의해 "d"로 대체되었기 때문입니다.
debug: 모든 이벤트를 출력하여 디버깅에 도움을 줍니다.let observable = Observable.of("a", "b", "c")
observable.debug("Observable values").subscribe()
Resources.total 사용하여 리소스 추적.DisposeBag을 사용하여 Observable 구독을 관리하므로, 올바른 메모리 관리가 중요합니다.TRACE_RESOURCES 플래그를 활성화해야 합니다. 이렇게 하면 RxSwift는 모든 할당된 리소스를 추적할 수 있습니다.Resources.total:Resources.total는 디버그 모드에서 현재 할당된 리소스의 총 수를 나타내는 전역 변수입니다. 메모리 누수가 의심될 때 이 값을 모니터링하여 증가하는지 확인할 수 있습니다.Resources.total 값이 증가하면 해당 부분에서 메모리 누수가 발생할 수 있습니다.TRACE_RESOURCES를 활성화합니다.Resources.total 값을 확인하여 이전에 비해 증가했는지 확인합니다.DisposeBag 및 다른 Rx 리소스가 올바르게 해제되었는지 확인해야 합니다.Queue)와 스케줄러(Scheduler)subscribeOn과 observeOn 연산자를 통해 연산의 흐름을 명확하게 제어할 수 있습니다.CurrentThreadSchedulerMainSchedulerSerialDispatchQueueSchedulerConcurrentDispatchQueueScheduleOperationQueueSchedulerlet uploadButton = UIButton() // 사진 업로드 버튼
uploadButton.rx.tap
.flatMapLatest {
uploadPhotoToServer() // 큰 사진 파일을 서버에 업로드하는 함수
.subscribeOn(ConcurrentDispatchQueueScheduler(qos: .background)) // 백그라운드 큐에서 업로드 작업을 수행
.observeOn(MainScheduler.instance) // 메인 큐에서 결과를 관찰
}
.subscribe(onNext: { _ in
// '업로드 완료!' 메시지 표시
showMessage("업로드 완료!")
})
.disposed(by: disposeBag)
subscribeOn을 사용하여 사진 업로드 작업을 백그라운드 큐에서 수행하도록 지정하였고, observeOn을 사용하여 그 작업의 결과 (업로드 완료)를 메인 큐에서 관찰하도록 하였습니다.subscribeOn 및 observeOn 연산자subscribeOn: Observable이 작동할 스케줄러를 지정합니다.observeOn: 관찰자가 이 Observable을 관찰할 스케줄러를 지정합니다.ImmediateScheduler 프로토콜을 구현해야 합니다. Scheduler 또는 Periodic Scheduler 프로토콜 중 하나를 구현해야 합니다.let observable = Observable.of(1, 2, 3)
// 1, 2, 3의 세 개의 요소를 발행하는 Observable을 생성합니다.
observable
.subscribeOn(SerialDispatchQueueScheduler)
// 이 메서드는 Observable이 어떤 스케줄러에서 작동할지 지정합니다.
// 여기서는 SerialDispatchQueueScheduler를 사용하여 Observable의 작업이 직렬 디스패치 큐 스케줄러에서 수행되도록 지정합니다.
// 이것은 주로 백그라운드 스레드에서 실행됩니다.
.observeOn(MainScheduler)
// 이 메서드는 관찰자가 어떤 스케줄러에서 Observable을 관찰할지 지정합니다.
// 여기서는 MainScheduler를 사용하여 관찰자가 메인 스레드에서 결과를 관찰하도록 지정합니다.
// 일반적으로 UI 업데이트와 같은 작업은 메인 스레드에서 수행되어야 하므로 이 메서드는 그러한 경우에 유용합니다.
.subscribe(onNext: { value in
print(value)
})
// 1
// 2
// 3