[iOS] - RxSwift 입문 (3)

Shawn·2021년 7월 10일
0

RxSwift

목록 보기
3/8
post-thumbnail

Operator 활용하기

지난 포스트에서 다룬 Operator들을 더 자세하게 다뤄보자.
공식 홈페이지에 잘 번역되어있는 Operator로 들어가면,

다양한 Operator들에 대해 설명을 해주고 있다.
여기서 중요한 것은, Reactive 만의 특별한 설명 방식인데,

Just() 를 다음과 같이 구슬로 설명하고 있다.
그대로 빨간공이 내려오면 종료 (dispose) 하겠다는 의미이다.

First도 한번 살펴보자.

첫번째 구슬이 내려오자마자 Dispose를 한다.
이런 것들은 코드를 통해서 확인해보고 싶어진다.


    @IBAction func exJust2() {
        Observable.just(["Hello", "World"])
            .subscribe(onNext: { arr in
                print(arr)
            })
            .disposed(by: disposeBag)
    }

전에 다뤘던 예문 2 코드에서,
single()를 얹어보자.

공식홈페이지에서 Single 을 클릭하니 First가 나오는 것으로 보아, 같은 기능인 것으로 보인다

    @IBAction func exJust2() {
        Observable.just(["Hello", "World"])
            .single()
            .subscribe(onNext: { arr in
                print(arr)
            })
            .disposed(by: disposeBag)
    }

그리고 subscribe를 이벤트 형태로 받아보자.

    @IBAction func exJust2() {
        Observable.just(["Hello", "World"])
            .single()
            .subscribe { event in
                switch event {
                case .next(let d):
                    print("next: \(d)")
                    break
                case .error(let error):
                    print("error: \(error)")
                    break
                case .completed:
                    print("completed")
                    break
                }
            }
            .disposed(by: disposeBag)
    }

subscribe 이벤트는 세가지 케이스가 있는데,
.next, .error, .completed 가 있다.
이대로 실행시켜보면 어떻게될까?
이렇게 나온다.
Just을 통해
Hello, World 배열이 "동시에" 내려왔기 때문에 한 구슬에 담겨 내려왔음을 알 수 있다.
그렇다면, Just가 아니라 From 으로 바꿔보겠다.
Single() 은 하나의 구슬이 내려오지 않으면 에러를 뱉기 때문에,
next를 통해 Hello 구슬이 내려온 뒤, 아직 World 구슬이 내려오지 않고 남아있는 것을 확인한 후 Error을 출력한다.

World 를 지우면,

예상대로, Hello 이후에 Completed가 출력되는 것을 볼 수 있다.

Scheduler

    @IBAction func exMap3() {
        Observable.just("800x600")
            .observeOn(ConcurrentDispatchQueueScheduler(qos: .default))
            .map { $0.replacingOccurrences(of: "x", with: "/") }
            .map { "https://picsum.photos/\($0)/?random" }
            .map { URL(string: $0) }
            .filter { $0 != nil }
            .map { $0! }
            .map { try Data(contentsOf: $0) }
            .map { UIImage(data: $0) }
            .observeOn(MainScheduler.instance)
            .subscribe(onNext: { image in
                self.imageView.image = image
            })
            .disposed(by: disposeBag)
    }

이렇게 observeOn(스케쥴러) 를 이용해서 해결할 수 있다.
ConcurrentDispatchQueueScheduler 로 비동기로 사진을 불러온다.
두 줄이 새로 추가됐는데, observeOn이 두줄 추가됐다.

윗 줄의 .observeOn 아래로 또다시 .observeOn이 나오기 전까지의 Operator 들은 비동기로 진행된다.
그러다가 다시 메인 쓰레드로 접근하게 하는 observeOn(MainScheduler.instance) 이 호출된 이후 아래의 subscribe은 메인에서 진행된다. (UI 이기 때문에 메인에서!)

실행시켜보면, 이미지가 불러오는중에도 드래그가 잘 되는 것을 확인 할 수 있다.
Main에서 이미지를 Url 에서 불러오는 것이 아니라,
Thread1 에서 이미지를 받아오고 있다.
Main Thread에 있는 UI들은 어떠한 제약도 받지 않는다.

굳이 구역을 정해서 비동기화를 쓰지 않고, subscribe 시작부터 전체 비동기화를 하고 싶다면, 아무곳에나 .subscribeOn(ConcurrentDispatchQueueScheduler)을 넣어주면 된다.
하지만 , observeOn(MainThread) 는 꼭 넣어줘야한다. UI를 꼭 다뤄야하기 때문,....

Side-Effect

Side effect란 간단히 말하면, 현재 함수 밖에 영향을 주는 코드를 말한다.

    @IBAction func exMap3() {
        Observable.just("800x600")
            .observeOn(ConcurrentDispatchQueueScheduler(qos: .default))
            .map { $0.replacingOccurrences(of: "x", with: "/") }
            .map { "https://picsum.photos/\($0)/?random" }
            .map { URL(string: $0) }
            .filter { $0 != nil }
            .map { $0! }
            .map { try Data(contentsOf: $0) }
            .map { UIImage(data: $0) }
            .observeOn(MainScheduler.instance)
            .subscribe(onNext: { image in
                self.imageView.image = image
            })
            .disposed(by: disposeBag)
    }

이 코드에서는 self.imageView.image = image 코드가
Side-Effect를 주고 있다.
Side-Effect를 사용하기 좋은 곳이 딱 두 곳 있는데,
이 코드의 .subscribe가 있고,
아래의 Do 가 있다.

Do

Do 함수를 살펴보자


오메나
여러 switch - case 문을 활용하기 좋아보이는 상황들이 있는데,
알맞은 상황에 맞춰서 side-effect를 주면 된다.
다음 포스트에서는 RxCocoa에 대해 알아본다.

profile
iOS 개발, Flutter 개발, Swift, Dart, 42 Seoul 3기

0개의 댓글