Observable
Rx 코드의 기반
- T 형태의 데이터 snapshot을 '전달' 할 수 있는 일련의 이벤트를 비동기적으로 생성하는 기능
- 하나 이상의 observers가 실시간으로 어떤 이벤트에 반응
- 세 가지 유형의 이벤트만 방출
RxSwift은 비동기 이벤트 기반 프로그래밍을 지원하여, iOS 앱 개발에서 매우 유용하다.
이러한 비동기 이벤트 기반 프로그래밍에 가장 중요한 요소 중 하나가 Observable이다.
next, error, completed
Observable은 RxSwift에서 가장 기본적인 개념 중 하나이다.
Observable은 이벤트를 발생시키는 객체로, 이벤트는 3가지 종류가 있다.
enum Event<Element> {
case next(Element) // 시퀀스의 다음 요소
case error(Swift.Error) // 시쿼스 실패와 에러
case completed // 완료로 인해 시퀀스 제거
- Next: Observable이 방출하는 가장 일반적인 이벤트이다. 이벤트는
next(Element)
형식으로 발생하며, 이벤트가 방출되면 구독자(subscriber)는 해당 값을 받아들일 수 있다. - Error: Observable이 동작하는 도중 예외가 발생하면 이벤트가 발생하며,
error(error)
형식으로 구독자에게 전달된다. - Completed: Observable의 동작이 완료되면 이벤트가 발생한다. 이벤트는
completed()
형식으로 발생하며, 이후에는 더 이상 이벤트가 발생하지 않는다.
Observable
은 이벤트를 발생시키는 것 외에도, 이벤트를 조작하거나 변환하는 다양한 기능을 제공한다. 이러한 기능을 통해 데이터를 효율적으로 처리하고, 비동기적으로 처리되는 작업을 보다 쉽게 제어할 수 있다.
그림으로 보면 이벤트의 진행 방향이 우측으로 진행되고 있는데
첫 번째 그림에서는 우측에 막히는 게 없으므로 Next
이벤트를 계속해서 방출할 수 있다.
두 번째 그림에서는 작대기로 진행이 막혀있는데 Completed
이벤트를 방출하여 완전 종료될 수 있다.
세 번째 그림에서는 X표시가 있는데 이는 Error
를 방출하여 완전 종료될 수 있다.
RxSwift에서는 Observable
을 생성하고, 구독자(subscriber)를 등록하고,
이벤트를 전달하는 등의 다양한 작업을 수행할 수 있다.
따라서 RxSwift의 Observable
은 iOS 앱 개발에서 매우 중요한 역할을 수행하며,
RxSwift을 사용하여 비동기 이벤트 기반 프로그래밍을 보다 쉽게 구현할 수 있다.
실제 활용 예시
네트워킹을 통해 데이터를 받게되는 경우 에러를 방출할 수 있고 작업을 완료할 수 있다.
Network.download(file: "https://www...")
.subscribe(onNext: { data in
//임시 파일에 데이터 추가
},
onError: { error in
//사용자에게 에러 표현
},
onCompleted: {
//다운로드 된 파일 사용
})
이때, 구독을 통해 onNext
, onError
, onCompleted
의 경우에 따라 실행할 코드를 입력할 수 있다.
Operator(새로운 Observable을 만드는 연산자)
새로운 Observable
을 만드는 연산자들 중 대표적으로 Just
, Of
, From
, Defer
, Create
에 대해서 알아보자
Just
Just
함수는 하나의 요소를 가지는 Observable
을 생성한다.
이 함수는 주어진 요소를 방출하고 즉시 종료되는 Observable
을 만든다.
let just = Observable<[Int]>.just([1, 2, 3])
just.subscribe {print($0)}
// subscribe를 통해 작업을 수행하면 next, error, completed가 각각 실행된다.
// next([1, 2, 3])
// completed
just.subscribe(onNext: {print($0)})
// subscribe(onNext:)를 통해 작업을 수행하면 next만 실행된다.
// [1, 2, 3]
Of
Of
함수는 가변 인자로 전달된 요소들을 가지는 Observable
을 생성한다.
이 함수는 전달된 요소들을 순서대로 방출하고, 마지막 요소가 방출된 후 즉시 종료된다.
let of = Observable<[Int]>.of([1, 2, 3])
of.subscribe {print($0)}
// next([1, 2, 3])
// completed
of.subscribe(onNext: {print($0)})
// [1, 2, 3]
여기까지만 봤을 때 궁금증이 하나 생기는데, just
와 of
의 차이가 무엇인가?
just
는 하나의 이벤트만 생성하고,
of
는 여러 개의 이벤트를 생성한다.
From
From
함수는 배열, Dictionary
, Set
, Sequence
등의 컬렉션을 전달받아 Observable
을 생성한다.
From
함수는 전달된 컬렉션의 요소들을 순서대로 방출하고, 마지막 요소가 방출된 후 즉시 종료된다.
let from = Observable<Int>.from([1, 2, 3])
from.subscribe {print($0)}
// next(1)
// next(2)
// next(3)
// completed
from.subscribe(onNext: {print($0)})
// 1
// 2
// 3
여기까지 봤을 때 궁금증이 하나 또 생기는데, of
와 from
의 차이가 무엇인가?
of
는 요소를 하나씩 받아서 방출하고,
from
은 배열을 받아서 요소를 하나씩 방출한다.
Deferred
Deferred
함수는 Observable
을 생성하는 클로저를 전달받아 Observable
을 생성한다.
이 함수는 Observable
이 구독될 때마다 클로저를 실행하여 Observable
을 생성하고,
해당 Observable
을 반환한다.
var toggle: Bool = false
let factory = Observable<String>.deferred {
toggle.toggle()
if toggle {
return Observable.just("true")
} else {
return Observable.just("fasle")
}
}
for _ in 0...3 {
factory.subscribe(onNext: {
print($0)
})
.disposed(by: disposeBag)
}
deferred
문의 클로저 안에서 조건문을 만들어 원하는 Observable
을 생성해줄 수 있다.
Create
create
연산자는 Observable
을 처음부터 생성할 수 있게 해준다.
이를 사용하여 Observable
이 방출할 이벤트들의 시퀀스를 정의할 수 있다.
Observer
에는 onNext
, onError
, onCompleted
라는 세 가지 메서드가 있다.
onNext
를 사용하여 값을 방출하고, onError
를 사용하여 오류를 방출하며,
onCompleted
를 사용하여 시퀀스가 완료되었음을 알릴 수 있다.
create
로 생성한 Observable
을 구독할 때, 일반적으로 subscribe(onNext:onError:onCompleted:)
메서드를 사용하여 Observable에서 값, 오류 또는 완료 이벤트가 방출될 때 실행할 코드를 지정한다.
Observable
에서 이벤트가 방출될 때 실행할 코드를 지정하려면 subscribe(_:)
메서드를 사용할 수도 있다.
create
는 저수준 연산자이므로 주의해서 사용해야 합니다.
일반적으로 just
, of
, from
, deferred
와 같이 RxSwift에서 제공하는 고수준 연산자를 사용하는 것이 좋다.
Observable.create {
$0.onNext(1)
$0.onError(MyError.error)
$0.onCompleted()
return Disposables.create()
}
.subscribe {
print($0)
}
.disposed(by: disposeBag)
// next(1)
// error(error)
// 이때 completed는 출력되지 않는다. error를 발생시키고 시퀀스가 멈췄기 때문이다.
Observable.create {
$0.onNext(1)
$0.onCompleted()
$0.onError(MyError.error)
return Disposables.create()
}
.subscribe {
print($0)
}
.disposed(by: disposeBag)
// next(1)
// completed
// 이때 error는 출력되지 않는다. completed를 발생시키고 시퀀스가 멈췄기 때문이다.
위에서 다른 코드를 보면 궁금증이 하나 생기는데
왜 subscribe(_:)
와 subscribe(onNext:)
가 별도로 있는것일까?
이유는 바로 switch문을 사용할 필요를 줄여주기 때문이다.
subscribe(_:) 를 사용하게 되면 next, error, completed가 모두 실행되기 때문에
원하는 시퀀스만 내가 골라서 실행해 주기 위해서 switch문을 사용해야하는 번거로움이 있는데
subscribe(onNext:onError:onCompleted:)를 사용하면 원하는것만 선택적으로 구현하면 된다.
Observable.create {
$0.onNext(1)
$0.onCompleted()
return Disposables.create()
}
.subscribe(onNext: {
print($0)
})
.disposed(by: disposeBag)
// 1
// 이때 completed는 출력되지 않는다. onNext만 실행했기 때문이다.
Observable.create {
$0.onNext(1)
$0.onCompleted()
return Disposables.create()
}
.subscribe {
switch $0 {
case .next(let next):
print(next)
case .error(let error):
print(error)
case .completed:
print("completed")
}
}
.disposed(by: disposeBag)
// 1
// completed
// switch문을 통해 onNext(1)과 onCompleted()를 걸러줬다.
참고하면 좋을 사이트: RxMarbles