본문 바로가기
Programming Paradigm/RxSwift

Materialize/dematerialize

by 탄이. 2020. 5. 16.

fimuxd/RxSwift

https://rhammer.tistory.com/304

Materialize/dematerialize

third party 프레임워크에 의해 생성될 수 있는, sequence 제어가 제한되거나 제어가 불가능해서 발생하는 에러를 처리하는 해결책.

관찰 가능 이벤트를 관찰 가능 이벤트로 변환하려는 경우가있을 수 있습니다. 이것이 유용한 일반적인 시나리오 중 하나는 관찰 가능한 속성이있는 관찰 가능 개체를 제어 할 수없고 외부 시퀀스가 ​​종료되지 않도록 오류 이벤트를 처리하려는 경우입니다.

  • materialize 연산자는 어떤 sequence든 Event<T> enum sequence로 변환한다.
    • Original
      • Data → X
      • Data → Completed
    • Materialized
      • Event<Data> → Event<Error>
      • Event<Data> → Event<Completed>
  • 이 연산자를 이용하면 적절한 연산자와 여러가지 handler로 조작되는 암시적인 sequence들을 명시적으로 변환할 수 있다.
  • 따라서 onNext, onError, onCompleted는 각각의 함수로써 조작될 수 있다.
  • dematerialize를 사용하여 notification sequence를 뒤집을 수 있다.
    • Materialized
      • Event<Data> → Event<Error>
      • Event<Data> → Event<Completed>
    • Dematerialize
      • Data → X
      • Data → Completed
  • materialize와 dematerialize는 보통 함께 쓰인다. 이 둘을 함께 쓰면 원본 observable을 완전히 분해할 수 있다. 다만, 특정 상황을 처리할 수 있는 다른 옵션이 없을 때만 신중하게 사용해야 한다.
  • 이 두가지 연산자를 병합해서 커스텀한 이벤트 기록기를 만들 수 있다.
observableToLog.materialize() 
	.do(onNext: { (event) in 
    	myAdvancedLogEvent(event) 
    }) 
    .dematerialize()

Example in Raywenderlich RxSwift Book

  • Materialize
    • Observable<Int> → Observable<Event<Int>>
  • Dematerialize
    • Observable<Event<Int>> → Observable<Int>
struct Student {
	var score: BehaviorSubject<Int>
}

enum MyError: Error {
	case anError
}

let ryan = Student(score: BehaviorSubject(value: 80))
let charlotte = Student(score: BehaviorSubject(value: 100))

let student = BehaviorSubject(value: ryan)

let studentScore = student
	.flatMapLatest {
		$0.score
	}
studentScore
	.subscribe(onNext: {
		print($0)
	})
	.disposed(by: disposeBag)

ryan.score.onNext(85)
ryan.score.onError(MyError.anError)
ryan.score.onNext(90)

student.onNext(charlotte)

// 80
// 85
// Received unhandled error: RxSwiftPlayground.playground:....

Materialize

let studentScore = student
	.flatMapLatest {
		$0.score.materialize()
	}

// next(80)
// next(85)
// error(anError)
// next(100)

Dematerialize

studentScore
	.filter {
		guard $0.error == nil else {
			print($0.error!)
			return false
		}

		return true
	}
	.dematerialize()
	.subscribe(onNext: {
		print($0)
	})
	.disposed(by: disposeBag)

// 80
// 85
// anError
// 100

댓글