ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [RxSwift] RxSwift 맛보기
    🧃RxSwift 2022. 10. 25. 01:06

     

    Iterator Protocol

    • 컬렉션을 반복 순회하는 next() 메서드를 통해 컬렉션의 반복 상태를 캡슐화함
    • Element: 반복 순회하며 가져온 요소
    • associatedtype (연관타입)으로 지정함으로써 순회해서 가져온 요소의 타입을 지정할 수 있음!
    • next() 메소드는 시퀀스에 있는 다음 요소를 반환하거나, 시퀀스의 마지막인 경우 nil 을 반환함!
    public protocol IteratorProtocol {
        associatedtype Element
    		public mutating func next() -> Self.Element?
    }
    

     

    Sequence Protocol

    • Sequence Protocol을 채택해야만 for…in 순환문으로 반복 순회가 가능함
    • Iterator Protocol을 채택해야함!
    • makeIterator() 메소드는 직접 호출할 필요는 없으며 스위프트 런타임시 for...in 순환문을 사용할 때 자동으로 호출됨
    • RxSwift에서 Sequence는 반복하고 있는 작업을 말함
    public protocol Sequence {
        associatedtype Iterator: IteratorProtocol
        public func makeIterator() -> Self.Iterator
    }
    
    for a in array {
    // 해당 반복문을 가능하도록 하는 프로토콜이 Sequence 이다!
    }
    

     

    RXSwift

    • AlamoFire와 같은 라이브러리(tool)일 뿐임!
    • 서드파티앱
    • 코드를 외워서 짜는 것이 아니고 다양한 예제들을 보면서 학습 해보면 됨!
    • operator가 엄청 많음!(고차함수와 같은 것)
    • operator에 빠지지 말고 만들어진 메서드에 불과하다는 것을 생각하고 사용하면 됨!
    • 디버깅이 어려움!

     

    Observable

    • 계속 이벤트를 전달함!
    • Obsever가 없다면 아무 처리를 할 수 없음!
    • 나중에 Observer가 생긴다면 생성 이후부터 처리가능함!
    • subscribe를 할 수 없음

     

    LifeCycle

    1. Create 연산자를 통해 Observable을 생성함 (보통 구현되어 있는 Operator를 사용함)
    2. Subscribe가 되면 Observable이 실행됨
    3. next를 통해 이벤트(제스쳐, 인스턴스 등)을 Emit함
    • Lifecycle 중 오류가 발생한다면 error 이벤트를, 정상적으로 모든 이벤트가 완료된다면 completed를 Notification함
    • deinit 되는 시점, Sequence가 종료되는 시점에 Dispose가 됨
    • error 또는 completed를 전달받으면 Sequence가 종료되고 종료된 이후에는 더 이상 이벤트가 발생하지 않음 즉, Observable에 대한 재사용이 불가능함
    • Emit: Next(여러번 발생 가능) - 점진적 다운로드, 최신 데이터 전달 → Append Buffer
    • Notification: Completed(지속적 방출 옵션X) - 다운로드 완료 → ImageView Image(기능적인 부분에서만 발생)
    • Notification: Error(지속적 방출 옵션X) - 디코딩 실패, 상태 코드 오류, 네트워크 연결 유실 → Alert(기능적인 부분에서만 발생)

     

    Finite observable sequences

    • 유한한 시퀀스가 사용되는 곳은 예를 들면 끝이 나면 자연스럽게 종료되어야 하는 동작인 다운로드와 같은 것을 말함!
    • ex) iOS 앱에서 인터넷에서 파일을 다운로드하는 상황
      1. 다운로드를 시작하고 들어오는 데이터를 관찰하기 시작합니다.
      2. 그런 다음 파일의 일부가 도착할 때 data 의 chunk 를 반복적으로 수신합니다.
      3. 네트워크 연결이 끊어지면 다운로드가 중지되고 연결 시간이 초과되어 오류가 발생합니다.
      4. 또는, 파일의 모든 데이터를 다운로드하게 되면 성공적으로 완료됩니다.
    API.download(file: "<http://www>...")
       .subscribe(
         onNext: { data in
          
         },
         onError: { error in
           
         },
         onCompleted: {
           
         }
       )
    

     

    Infinite observable sequences

    • 위에서 본 자연스럽게 종료되어야 하는 다운로드와 달리 무한한 시퀀스가 있음
    • 기본적으로 UI 이벤트와 같은 것들은 무한한 시퀀스임
    • ex) 앱이 기기가 세로인지 가로인지에 대해서 대응하는 코드를 생각해봤을때
      1. NotificationCenter로부터 UIDeviceOrientationDidChanged 알림에 대한 observer 로 클래스를 추가할 수 있음!
      2. 그런 다음 방향 변경을 처리하기 위해 method callback 을 제공해야 합니다. UIDevice 에서 현재 방향을 가져와서 최신 값에 따라 반응해야 합니다.
      3. 그럼 아래와 같이 방향 전환이 되었을 때인 subscribe 상태에서 switch나 if문과 같이 조건문을 활용해서 분기처리를 해볼 수 있음
    UIDevice.rx.orientation
      .subscribe(onNext: { current in
        switch current {
        case .landscape:
          // Re-arrange UI for landscape
        case .portrait:
          // Re-arrange UI for portrait
        }
      })
    
    • 이러한 방향 변경 시퀀스에는 끝이 없고 시퀀스는 거의 무한대이고 상태를 저장하므로 관찰을 시작할 때 항상 초기 값이 있음
    • 사용자가 기기를 절대로 회전하지 않는 경우도 있지만 그렇다고 이벤트의 시퀀스가 종료되는 것은 아니고 이벤트가 발생하지 않는 것을 의미함

     

    Scheduler

    • 스케쥴러는 작업을 어디서 수행할지에 관한 작업을 추상화함
    • Main thread에서 수행할지, background에서 수행할지 등을 정할 수 있게 해줌
    • RxSwift에서는 스케줄러를 통해 Observable을 생성하는 작업을 어디서 할지 그리고 Observer가 시퀀스를 관찰하는 작업을 어디서 할지 정할 수 있음

     

    Observer

    • 이벤트에 대해서 계속 관찰하고 있어야함!
    • 이벤트가 발생하면 아래와 같이 이벤트에 대한 처리를 함!
    • 특정 액션에 대해 실행을 시켜주는 트리거의 역할을 함!
    • Subscribe - 구독하면 그때부터 Observer가 이벤트에 대해서 관찰하며 아래와 같이 구동하고 있는 대상의 다음 값, 에러가 났을 경우, 완료된 경우에 대한 시점에 대한 분기처리가 가능함
    Observable.just(itemsA)
                .subscribe { value in
                    print("just - \\(value)")
                } onError: { error in
                    print("just - \\(error)")
                } onCompleted: {
                    print("just completed")
                } onDisposed: {
                    print("just disposed")
                }
                .disposed(by: disposeBag)
    
    • Dispose - 어떤 조건을 만족했을 경우 Dispose를 주면 구독 취소 가능
    • Bind - subscribe에서 onNext 매개변수만 가져와서 사용하기 때문에 error 이벤트를 받지 않는 다는 특성이 있음! 그러므로 UI 부분을 처리해줄때 적합함!
    Observable.combineLatest(signName.rx.text.orEmpty, signEmail.rx.text.orEmpty) { value1, value2 in
                return "name은 \\(value1), 이메일은 \\(value2)입니다"
            }
            .bind(to: simpleLabel.rx.text)
            .disposed(by: disposeBag)
    
    • RxCocoa - RxSwift는 기능에 관련된 것이지만 RxCocoa는 RxSwift 기반의 UI에 관련된 것!
    • 항상 마지막에 Dispose 필수!
    • 이벤트를 전달할 수 없음

     

    Operator

    • just - element를 하나만 받을 수 있고 한번만 emit함
    //Just: observable의 object를 한번만 Emit함(하나의 object만 담기 가능)
        func exmpleJust() {
            Observable.just([1,2,3,4,5])
                .subscribe { event in
                    print(event)
                }
                .disposed(by: disposeBag)
        }

    • of - element를 여러 개 받을 수 있고 값의 개수 만큼 emit함
    //Of: observable의 object들을 모두 Emit함(여러개의 object 담기 가능)
        func exmpleOf() {
            Observable.of("💩","👻","👾","🤖","🤡")
                .subscribe { element in
                    print(element)
                }
                .disposed(by: disposeBag)
        }

    • from - 배열의 element의 요소들의 개수만큼 방출함
    //from: 배열만 받을 수 있고 배열의 원소의 개수마다 emit함
        func exampleFrom() {
            Observable.from([1,2,3,4,5])
                .subscribe { value in
                    print(value)
                }
                .disposed(by: disposeBag)
        }
    

    • repeatElement - 계속 방출함
    • .take(Int) - repeat에 대해서 몇 번 방출할지를 제한 가능
    //repeatElement: .take(i) i번 만큼 observable로 방출된 요소를 출력함
        func exmpleRepeatElement() {
            Observable.repeatElement("🔴")
                .take(3)
                .subscribe(onNext: { print($0) })
                .disposed(by: disposeBag)
        }
    

    • range - start부터 count 크기 만큼의 observable로 각각 방출된 요소에 대해서 값을 Double로 변환 후 출력함
    //range: start부터 count 크기 만큼의 observable로 각각 방출된 요소에 대해서 값을 Double로 변환 후 출력함
        func exampleRange() {
            Observable.range(start: 1, count: 10)
                .subscribe { value in
                    print(Double(value))
                }
                .disposed(by: disposeBag)
        }
    

    • interval(.seconds(Int)) - 정해진 시간마다 계속 방출함
    • create - 커스텀한 observable 시퀀스를 생성해주며 하나의 element만 담을 수 있고 한번만 emit한 후에 출력함
    //create: 커스텀한 observable 시퀀스를 생성해주며 하나의 element만 담을 수 있고 한번만 emit한 후에 출력함
        func exampleCreate() {
            let myJust = { (element: String) -> Observable<String> in
                return Observable.create { observer in
                    observer.on(.next(element))
                    observer.on(.completed)
                    return Disposables.create()
                }
            }
                
            myJust("🔴")
                .subscribe { print($0) }
                .disposed(by: disposeBag)
        }
    

    • combineLatest - 여러 개의 element를 등록 가능하고 등록된 개체 중 하나만 변경되어도 실행됨
    • .orEmpty - 옵셔널 값 벗겨줌
    • .tap - touchUpInside와 같음
    • generate - initialState - 초기값 설정, condition - 조건 부여, iterate - 시퀀스마다 어떻게 반복할지 이렇게 앞에 지정해준 초기값, 마지막 값에 대한 조건, 반복조건에 대한 observable을 emit 후 출력함
    //generate: initialState - 초기값 설정, condition - 조건 부여, iterate - 시퀀스마다 어떻게 반복할지
        func exampleGenerate() {
            Observable.generate(
                    initialState: 0,
                    condition: { $0 < 3 },
                    iterate: { $0 + 1 }
                )
                .subscribe(onNext: { print($0) })
                .disposed(by: disposeBag)
        }
    

    • deffered - 각각의 시퀀스마다 다른 subscriber을 지정해줄 수 있는 커스텀한 observable 생성 후 emit
    //deffered: 각각의 시퀀스마다 다른 subscriber을 지정해줄 수 있는 커스텀한 observable 생성 후 emit
        func exampleDeffered() {
            var count = 1
            
            let deferredSequence = Observable<String>.deferred {
                print("Creating \\(count)")
                count += 1
                
                return Observable.create { observer in
                    print("Emitting...")
                    observer.onNext("🐶")
                    observer.onNext("🐱")
                    observer.onNext("🐵")
                    return Disposables.create()
                }
            }
            
            deferredSequence
                .subscribe(onNext: { print($0) })
                .disposed(by: disposeBag)
            
            deferredSequence
                .subscribe(onNext: { print($0) })
                .disposed(by: disposeBag)
        }
    

    • error - item을 emit하지 않고 error와 함께 즉시 종료되는 observable을 생성함
    • doOn - 각 이벤트에 대해 do에 작성한 sideEffect 작업을 호출하고 원래 이벤트인 .subscribe를 반환함
    func exampleDoOn() {
            Observable.of("🍎", "🍐", "🍊", "🍋")
                .do(onNext: { print("Intercepted:", $0) }, afterNext: { print("Intercepted after:", $0) }, onError: { print("Intercepted error:", $0) }, afterError: { print("Intercepted after error:", $0) }, onCompleted: { print("Completed")  }, afterCompleted: { print("After completed")  })
                .subscribe(onNext: { print($0) })
                .disposed(by: disposeBag)
        }
    

     

    Subject

    • Emit & Subscribe를 동시에 수행 가능함

     

Designed by Tistory.