Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
Tags
- map
- UITextView
- Xcode
- Human interface guide
- Protocol
- collectionview
- 리펙토링
- HIG
- rxswift
- 애니메이션
- clean architecture
- swiftUI
- UICollectionView
- uiscrollview
- uitableview
- 클린 코드
- swift documentation
- tableView
- MVVM
- combine
- 스위프트
- 리펙터링
- Refactoring
- 리팩토링
- SWIFT
- RxCocoa
- ribs
- Clean Code
- Observable
- ios
Archives
- Today
- Total
김종권의 iOS 앱 개발 알아가기
[iOS - swift] RxSwift의 deferred 이해하기 본문
RxSwift의 Deferred
- 단어 그대로, deferred 함수에는 파라미터로, Observable을 리턴하는 클로저를 받아서 그 클로저를 내부적으로 저장해놓았다가 해당 Observable이 필요할 때 그 클로저에 접근하여 사용
- Observable을 지연시키는 것이 아닌, deferred의 인수로 들어간 클로저안의 동작을 지연시키는 것임을 주의
extension ObservableType {
public static func deferred(_ observableFactory: @escaping () throws -> Observable<Element>)
-> Observable<Element> {
Deferred(observableFactory: observableFactory)
}
}
ex) Observable을 리턴하는 메소드 준비
private func firstObservable() -> Observable<Void> {
.create { [weak self] observer in
observer.onNext(())
observer.onCompleted() // concat은 onCompleted 방출해야 아래 스트림이 동작
return Disposables.create()
}
}
private func secondObservable() -> Observable<Void> {
.create { [weak self] observer in
observer.onNext(())
observer.onCompleted()
return Disposables.create()
}
}
- 아래 1)번과 2번 동작 차이는 없는것을 주의
- 주의) concat은 onCompleted()가 방출될때 아래 스트림 동작하므로 위 observable에서 onCompleted() 실행 필수
- deferred를 사용하면 secondObservable() 메소드 호출이 지연되지만, secondObservable()의 메소드에는 Observable을 리턴하는 메소드밖에 없으므로 deferred가 없이 호출하는 상태(= 위에서 아래로 Observable 스트림 수행)와 동일
// 1)
Observable
.concat(
firstObservable(),
secondObservable()
)
.subscribe()
.disposed(by: disposeBag)
// 2)
Observable
.concat(
firstObservable(),
.deferred { [weak self] in self?.secondObservable() ?? .empty() }
)
.subscribe()
.disposed(by: disposeBag)
- Observable을 지연시키는 것이 아닌, deferred의 인수로 들어간 클로저안의 동작을 지연시키는 것임을 이해할 것
ex) 전역으로 someProperty를 두고, nil값을 가지며 concat에서 상위 스트림인 firstObservable()에서 초기화를 한 후 하위 스트림인 secondObservable()에서 강제 unwrpping해도 크래시가 나지 않으며 정상 초기화 될 것을 확인
class ViewController: UIViewController {
var someProperty: Int?
let disposeBag = DisposeBag()
override func viewDidLoad() {
super.viewDidLoad()
Observable
.concat(
firstObservable(),
secondObservable()
)
.subscribe()
.disposed(by: disposeBag)
}
private func firstObservable() -> Observable<Void> {
.create { [weak self] observer in
print("first")
self?.someProperty = 1
observer.onNext(())
observer.onCompleted()
return Disposables.create()
}
}
private func secondObservable() -> Observable<Void> {
.create { [weak self] observer in
print("second")
print(self?.someProperty!)
observer.onNext(())
observer.onCompleted()
return Disposables.create()
}
}
}
ex) 만약 deffered를 사용하지 않고 secondObservable()에 접근하면 아래처럼 Observable이 아닌 밖에서 someProperty 강제 unwrapping하는 경우 크래시 발생
- deferred를 사용하지 않으면 상위 Observable이 끝나기 전에, someProperty!에 접근하게 되므로 크래시 발생
Observable
.concat(
firstObservable(),
secondObservable()
)
.subscribe()
.disposed(by: disposeBag)
private func secondObservable() -> Observable<Void> {
print("second")
print(someProperty!) // crash!
return .just(())
}
- 이 때 사용하는 쪽에서 deferred로 접근하면 secondObservable()의 body 부분 접근까지 지연되어서 크래시 해결이 가능
Observable
.concat(
firstObservable(),
.deferred { [weak self] in self?.secondObservable() ?? .empty() } // <-
)
.subscribe()
.disposed(by: disposeBag)
private func secondObservable() -> Observable<Void> {
print("second")
print(someProperty!) // no crash
return .just(())
}
- 결론
- deferred 연산자는 Observable을 지연시키는 것이 아닌, deffered 안에 클로저로 주입한 해당 block 자체를 지연시키는 것
'iOS 응용 (swift)' 카테고리의 다른 글
Comments