1탄에서는 Rxswift
가 어떤식으로 동작되는지 파악할 수 있었다.
이제는 Rxswift
에서 많이 사용하는 Operator
의 내부를 파헤쳐보며 어떻게 동작하는지 확인해볼 것이다.
extension MyObservable {
static func create(_ task: @escaping (_ execute: @escaping (T) -> Void) -> Void) -> MyObservable<T> {
return MyObservable(task: task)
}
}
MyObservable.create { execute in
execute("\\(42)")
}
.subscribe { s in
print(s)
}
// 42
이 메서드는 생성자를 받아서 여기에서 생성자를 호출하고 생성해주는 역할을 하고 있다.
그래서 return
에서 MyObservable(task: task)
로 호출하고 생성하는 것을 볼 수 있다.
실행하는 곳에서 보면 42라는 생성자를 호출해서 생성한 다음 subscribe
에서 출력하는 것을 볼 수 있다.
extension MyObservable {
static func just(_ value: T) -> MyObservable<T> {
return MyObservable<T> { receiver in
receiver(value)
}
}
}
MyObservable.just(42)
.subscribe { i in print(i) }
// 42
`just`는 어떤 값을 받고 받은 것을 그대로 돌려주는 것을 의미한다. 그래서 `receiver`라는 용어라고 사용하고 있으며 받은 `value`를 바로 내보낸다. 이는 `task`를 대신 호출해주고 있다.
호출부에서 42를 받아서 바로 호출해주는 것을 볼 수 있다.
extension MyObservable {
static func from(_ value: [T]) -> MyObservable<T> {
return MyObservable<T> { receiver in
value.forEach { t in
receiver(t)
}
}
}
}
MyObservable.from([42, 41, 40])
.subscribe { i in
print(i)
}
// 42
// 41
// 40
just
에서는 값을 하나만을 전달하지만, from
에서는 값을 여러번 전달할 수 있다.
내부를 보면 forEach
로 반복문으로 내보내는 것을 볼 수 있다.
호출부에서 반복문으로 하나씩 출력되는 것을 볼 수 있다.
extension MyObservable {
func map<U>(_ mapper: @escaping (T) -> U) -> MyObservable<U> {
return MyObservable<U> { receiver in
self.subscribe { t in
receiver(mapper(t))
}
}
}
}
MyObservable.from([41, 42, 43])
.map { i in i * 2}
.subscribe { s in
print(s)
}
// 82
// 84
// 86
`rxswift`에서 `map`는 `execute`로 생성해서 들어온 값을 새로 생성해준다. 그래서 `subscribe`를 해야 실제 값을 전달하게되고 새로 값을 만들어서 전달하게 된다.
그래서 값을 새로 만들어서 재설정 해줄 수 있다.
호출부에서 보면 2씩 곱해서 새로 만들어서 내보내는 것을 볼 수 있다.
extension MyObservable {
func filter(_ filter: @escaping (T) -> Bool) -> MyObservable<T> {
return MyObservable<T> { receiver in
self.subscribe { t in
if filter(t) {
receiver(t)
}
}
}
}
}
MyObservable.from([42, 41, 40])
.filter { i in i % 2 == 0 }
.map { i in "\\(i)" }
.subscribe { i in
print(i)
}
// 42
// 40
`filter`는 이름 그대로 걸러내준다! 그래서 내보낼지 말지는 `filter`의 조건에 따라 결정된다.
내부 코드를 보면 t가 나오는데 여기에서 조건문으로 filter(t)
가 true
라면 receiver
에게 전달하고, 그게 아니라면 전달하지 않는다.
호출부에서 보게되면, 나머지가 0인 경우만 filter
에서 true
가 되어서 receiver
에게 전달된다.
extension MyObservable {
func flatMap<U>(_ mapper: @escaping (T) -> MyObservable<U>) -> MyObservable<U> {
return MyObservable<U> { receiver in
self.subscribe { t in
mapper(t).subscribe { u in
receiver(u)
}
}
}
}
}
MyObservable.from([42, 41, 40])
.filter { i in i % 2 == 0 }
.flatMap { i in MyObservable.just(i) }
.map { i in "\(i)" }
.map { s in Int(s) }
.filterNil()
.main()
.subscribe { i in
print("flamap \(i)")
}
// 42
// 40
`flatmap`는 `map`과의 차이점을 보게되면 `mapper` 파라미터의 반환값이 다른 것을 볼 수 있다.
동일하게 T를 받지만, map
에서는 U를 내보내고, flatMap
에서는 MyObservable<U>
를 반환한다.
이 의미로는, value
가 아니라 MyObservable<U>
반환값이 되어야 한다. 그래서 실제 가져온 값을 Observe
해서 바꾼 값을 receiver
에게 보내야 한다.
그래서 내부를 보면 subscribe
를 두번하는 것을 볼 수 있다.
mapper
로 이루어진 t를 다시 subscribe
해서 나온 값을 receiver
에게 전달하는 것을 볼 수 있다.
이름 그대로 더 평평하게 만들어준다는 것이다!
호출부를 보면 filter
로 걸러준 다음 flatMap
를 이용해서 값을 하나씩 보내도록 하고 이를 Int
타입으로 해서 내보내고 있다.
그래서 42, 40이 나오는 것이다.
extension MyObservable {
func filterNil<U>() -> MyObservable<U> where T == U? {
return filter { $0 != nil }.map { $0! }
}
}
MyObservable.from([42, 41, 40])
.filter { i in i % 2 == 0 }
.flatMap { i in MyObservable.just(i) }
.map { i in "\\(i)" }
.map { s in Int(s) }
.filterNil()
.subscribe { i in
print(i)
}
이 예시도 위에서 쓴 예시에서 사용한 것인데,
filterNil
에 대해 설명하도록 하겠다.
여기에서는 T를 내보내는 것을 U 타입으로 바꾸게 된다.
그래서 T가 U타입의 Optional
이면 Optional
뺀 것을 내보내겠다는 의미다.
그래서 nil
이 아니면 강제추출하겠다는 의미다!
extension MyObservable {
func main() -> MyObservable<T> {
return MyObservable<T> { receiver in
self.subscribe { t in
DispatchQueue.main.async {
receiver(t)
}
}
}
}
}
MyObservable.from([42, 41, 40])
.filter { i in i % 2 == 0 }
.flatMap { i in MyObservable.just(i) }
.map { i in "\\(i)" }
.map { s in Int(s) }
.filterNil()
.main()
.subscribe { i in
print(i)
}
마지막으로는 Main Thread
에서 실행되도록 만드는 코드다!
UI 작업과 같이 event
처리를 위해 Main thread
로 설정해줘야 하는 경우가 있다.
내부를 보면 자신과 동일한 것을 return 하고 있는데
전달하는 부분인
self.subscribe { t in
}
이 부분에는 global thread
로 보내고 그 내부에서 전달하는 것에서만 main thread
로 보내도록 구현되어 있다.
그래서 동일한 예시에서 main thread
로 보내야할 때 .main()
를 사용해서 만들어주고 있다.
주요 기능들에 대해 한번 내부를 보고 실제 어떻게 동작하는지 확인해보았다!
다음에서는 Subject에 대해 알아볼 예정이다!
-참고사이트-
곰튀김님 강의
https://reactivex.io