apple/UIKit & ReactiveX

[week2] 👀 Observserbles

lgvv 2021. 7. 8. 20:51

✅ 이번 시간에는 Observserbles에 대해서 알아볼 예정이야!

 

옵저버블 이제 조금 이해가 되기 시작했어. 여기장을 공부할떄는 너무 많아서 이게 과연 가능할까? 까지도 의문이 들더라.. 그래서 일단은 모든 걸 다 해볼 수는 없고, 그림이라도 한번씩 다 봐두면 이해가 되니까 이런 상황에서는 예전에 이런 그림이 있었던 것 같은데...? 하고서 가서 찾아쓰는 방법으로 공부의 방향을 설정했어.

 

아직 많이 안해서 그런지 여기까지 하니까 rx 뭔가 할만하다...? 이런 생각이 들기 시작했음!!

 

나의 소스코드 : https://github.com/lgvv/MyRxSwift

 

lgvv/MyRxSwift

나의 RxSwift 공부 기록장. Contribute to lgvv/MyRxSwift development by creating an account on GitHub.

github.com

 

 

 

 

http://reactivex.io/documentation/operators.html

 

ReactiveX - Operators

Introduction Each language-specific implementation of ReactiveX implements a set of operators. Although there is much overlap between implementations, there are also some operators that are only implemented in certain implementations. Also, each implementa

reactivex.io

https://github.com/lgvv/RxSwiftStudy/blob/main/week2.md

 

lgvv/RxSwiftStudy

RxSwift를 공부하는 Repository입니다.🐍. Contribute to lgvv/RxSwiftStudy development by creating an account on GitHub.

github.com

 

(목차)

1. 이론에 대해서 알아보자

2. emitting? 정확하게 어떤 의미일까?

3. 다시 한번 LifeCycle을 정리해보자

4. operator 입문 (just, from, empty, never, range)

5. 메모리 누수를 막기위해 DisposeBag() 을 사용해보자!

6. 간단한 활용 예시) 버튼 클릭 시에 텍스트 필드에 입력된 정보를 받아오기.

 

 

✅ 1. 이론에 대해서 알아보자

Observable은 다양한 이름으로 불려질 수 있다.

옵저버블이 여러 이름으로 불려요!

✅ 2. emitting? 정확하게 어떤 의미일까?

emitting

내가 emitter 쓰면서 이건 onNext? 와 관련하여 순서대로 들어온 데이터가 담기는 장소라고 생각했는데, 이런 의미라고 한다!!

 

✅ 3. 다시 한번 LifeCycle을 정리해보자

라이프 사이클 다시보자!

 

후 라이프 사이클 정말 중요한거 같다. 엄청 자주 보이네!!

 

✅ 4. operator 입문 (just, from) 

여기부터는 아래의 참고자료를 활용해서 작성했어!

- just : 단일 시퀀스로 내려보내줌

- from : 하나하나 따로 내려보내줌

이 두개는 공식문서의 operator 카테고리에서 creating observables에 속해.

이거 말고도 많은 오퍼레이터들이 여기 속하는데, 이건 나중에 따로 포스팅할게..!

 

그럼 이걸 어떻게 사용하는지도 중요하겠지?

 

예시에 사용할 부분.

    let stringSequence = Observable.just("this is string yo")
    let oddSequence = Observable.from([1, 3, 5, 7, 9])
    let dictSequence = Observable.from([1:"Rx",2:"Swift"])
    
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        
        print("----stringSequence:just---")
        stringSequence.subscribe { (event: Event<String>) in
            print(event)
        }.disposed(by: disposeBag)
        
        print("----oddSequence:from---")
        oddSequence.subscribe { (event: Event<Int>) in
            print(event)
        }.disposed(by: disposeBag)
        
        print("----dictSequence:from---")
        dictSequence.subscribe { (event: Event<(key: Int, value: String)>) in
          print(event)
        }.disposed(by: disposeBag)
        
        
    }

이런식으로 사용할 수 있어. 그럼 이거의 결과는 어떻게 나오는지는 조금만 더 내려보자.

여기서 눈에 띄는것은 변수에 옵저버블을 붙여서 사용했다는 것이다. 

옵저버블을 붙이면 아무것도 하지 않는데, 그 후에 중요한 작업이 뭐다? subscribe!! 이걸 해줘야 작동을 한다.

그리고 event 타입으로 캐스팅한게 보이는데, 저렇게 캐스팅하면 딕셔너리까지 문제 없이 받을 수 있다.

그럼 딕셔너리나 배열은 just로 받으면? 뭉떵이로 내려오는데, 이러면 사용성이 ㄷ...

위의 코드에 대한 결과

 

✅ 위에가 just와 from이었다면 같은 카테고리의 empty, never, range도 알아보자.

        print(" ===== never ===== ")
        let neverSequence = Observable<String>.never()
        let neverSequenceSubscription = neverSequence
            .subscribe { _ in
                print("This will never be printed")
        }
        neverSequenceSubscription.disposed(by: disposeBag)
        
        print(" ===== empty ===== ")
        Observable<Int>.empty()
            .subscribe { event in
                print(event)
            }
            .disposed(by: disposeBag)

이렇게 작성할 수 있어.

그럼 이거에 대한 결과는 어떻게 나올까?

위의 코드에 대한 결과

네버는 절대 실행되지 않고 엠프티는 그래도 컴플릿은 작동되는걸 확인할 수 있어!

never가 사용되는 이유
empty를 사용하는 이유

 

그럼 range는 어떻게 쓰이는 것일까?

        print(" ===== range ===== ")
        Observable.range(start: 1, count: 10)
            .subscribe { print($0) }
            .disposed(by: disposeBag)

range 결과

이렇게 사용된다! 마치 for문 같은데 그렇게 어렵지 않습니다!

 

✅ 5. 메모리 누수를 막기위해 DisposeBag() 을 사용해보자!

week1에서도 설명하고 다른 포스팅에서도 설명했지만, 메모리를 꼭 다시 놔줘야해. rx는 누수가 발생할 확률이 큰데, 우리는 [weak self] 를 통해서 막을 수도 있지만, 이렇게 하면 조금 더 간편해 지겠지? 

다만 이것도 단점이 존재해.

네트워크 작업을 비동기로 처리하는데, 중간에 우리가 모종의 이유로 완료되기 전에 취소하게 된거야. 그럼 중단 되어야겠지? 혹은 완료되기 전에 뷰가 dismiss된거야. 이 경우에도 메모리를 그냥 잡고 할게 없이 붕 떠버려. 이렇게 누수가 발생하는데, 이걸 사용해서 viewDidDisAppear에 이걸 실행시키면 자동으로 다 끌고나가서 안전하게 종료 가능!!

직접 subscription.dispose()이렇게!! 하지만 직접 호출하는 것은 bad code smell 이다. Thread가 다를 때 Observable을 사용하기도 전에 메모리를 비워주는 일이 발생할 수 있음.

 

✅ 6. 간단한 활용 예시) 버튼 클릭 시에 텍스트 필드에 입력된 정보를 받아오기.

여기는 예제 파일을 직접 보면서 쉽게 할 수 있어.

override viewDidLoad() {
        button.rx.tap.subscribe(onNext: { next in
            self.myJust(element: self.textField.text ?? "null")
                .subscribe { s in print(s) }
        }).disposed(by: disposeBag)
}

   func myJust<E>(element: E) -> Observable<E> {
        return Observable.create { observer in
            observer.on(.next(element))
            observer.on(.completed)
            return Disposables.create()
        }
    }

이 경우에는 이렇게 사용할 수 있어. 

 

 

 

 

(참고)

https://trilliwon.medium.com/rxswift-%EA%B8%B0%EB%B3%B8-%EC%9D%B5%ED%9E%88%EA%B8%B0-1-d4d77ce63ca8

 

RxSwift 기본 익히기 (1) — 10 분짜리 (updated)

Rx는 충분히 공부하고 사용할 만한 가치가 있는 기술이라고 생각합니다.

trilliwon.medium.com

 

'apple > UIKit & ReactiveX' 카테고리의 다른 글

[week4] Filtering Observables  (0) 2021.07.10
[week3] Subjects  (0) 2021.07.10
🐉 RxSwift(Operators) Creating Observables  (0) 2021.07.09
[week1] Hello RxSwift 🖐  (0) 2021.07.07
RxSwift 4시간 만에 끝내기  (0) 2021.07.06