관리 메뉴

김종권의 iOS 앱 개발 알아가기

[RxSwift] 9. Combining Operators 본문

RxSwift/RxSwift 기본

[RxSwift] 9. Combining Operators

jake-kim 2020. 6. 5. 14:21

1. Prefixing and concatenating

- Observable끼리 합치는 것

 

1) startWith(value)

- 기존 리스트에 첫 번째에 추가

startWith연산자

 

example(of: "startWith") {
  // 1
  let numbers = Observable.of(2, 3, 4)
  
  // 2
  let observable = numbers.startWith(1)
  _ = observable.subscribe(onNext: { value in
    print(value)
  })
}

2) concat([])

example(of: "Observable.concat") {
  // 1
  let first = Observable.of(1, 2, 3)
  let second = Observable.of(4, 5, 6)
  
  // 2
  let observable = Observable.concat([first, second])
  
  observable.subscribe(onNext: { value in
    print(value)
  })
}

※ 단, Observable.contat()에 들어가는 것은 무조건 동일 타입이어야 함

 

3) merge

두 개의 Observable Sequence를 하나의 Observable Sequence로 합침

 

example(of: "merge") {
  // 1
  let left = PublishSubject<String>()
  let right = PublishSubject<String>()
  
  // 2
  let source = Observable.of(left.asObservable(), right.asObservable())
  
  // 3
  let observable = source.merge()
  let disposable = observable.subscribe(onNext: { value in
    print(value)
  })
  
  // 4
  var leftValues = ["Berlin", "Munich", "Frankfurt"]
  var rightValues = ["Madrid", "Barcelona", "Valencia"]
  repeat {
      switch Bool.random() {
      case true where !leftValues.isEmpty:
          left.onNext("Left:  " + leftValues.removeFirst())
      case false where !rightValues.isEmpty:
          right.onNext("Right: " + rightValues.removeFirst())
      default:
          break
      }
  } while !leftValues.isEmpty || !rightValues.isEmpty
 
  // 5
  left.onCompleted()
  right.onCompleted()
}

/* prints
Left:  Berlin
Right: Madrid
Left:  Munich
Right: Barcelona
Left:  Frankfurt
Right: Valencia
*/

4) combineLatest

하나의 이벤트만 저장 가능했던 Observable Sequence를 여러 개의 이벤트를 저장하게끔 함

- left를 기준으로해서 right가 나중에 나오면 모두 left에서의 최신 값과 매칭

example(of: "combineLatest") {
    let left = PublishSubject<String>()
    let right = PublishSubject<String>()
    
    // 1
    let observable = Observable.combineLatest(left, right) {
        lastLeft, lastRight in
        "\(lastLeft) \(lastRight)"
    }
    
    let disposable = observable.subscribe(onNext: { value in
        print(value)
    })
    
    // 2
    print("> Sending a value to Left")
    left.onNext("Hello,")
    print("> Sending a value to Right")
    right.onNext("world") // print : Hello, world
    print("> Sending another value to Right")
    right.onNext("RxSwift") // print : Hello, RxSwift
    print("> Sending another value to Left")
    left.onNext("Have a good day,") // print : Have a good day RxSwift
    
    left.onCompleted()
    right.onCompleted()
}

 

ex2)  현재 시간으로 로그 남기기

example(of: "combine user choice and value") {
  let choice: Observable<DateFormatter.Style> = Observable.of(.short, .long)
  let dates = Observable.of(Date())
  
  let observable = Observable.combineLatest(choice, dates) {
    format, when -> String in
    let formatter = DateFormatter()
    formatter.dateStyle = format
    return formatter.string(from: when)
  }
  
  _ = observable.subscribe(onNext: { value in
    print(value)
  })
}

 

5) zip

- combineLatest와 최근의 이벤트들과 짝지어지지만, 갯수 제한이 생김

 

example(of: "zip") {
    enum Weather {
        case cloudy
        case sunny
    }
    let left: Observable<Weather> = Observable.of(.sunny, .cloudy, .cloudy, .sunny)
    let right = Observable.of("Lisbon", "Copenhagen", "London", "Madrid", "Vienna")
    let observable = Observable.zip(left, right) { weather, city in
        return "It's \(weather) in \(city)"
    }
    _ = observable.subscribe(onNext: { value in
        print(value)
    })
}

/* prints :
 It's sunny in Lisbon
 It's cloudy in Copenhagen
 It's cloudy in London
 It's sunny in Madrid
 */

 

2. Triggers

특정 시점에 observable들을 받아들여야 하는 경우에 이용

 

1) withLatestFrom

example(of: "withLatestFrom") {
  // 1
  let button = PublishSubject<Void>()
  let textField = PublishSubject<String>()
  
  // 2
  let observable = button.withLatestFrom(textField)
  _ = observable.subscribe(onNext: { value in
    print(value)
  })
  
  // 3
  textField.onNext("Par")
  textField.onNext("Pari")
  textField.onNext("Paris")
  button.onNext(())
  button.onNext(())
}

/*
Paris
Paris
*/

2) sample

- withLatestFrom과 기능 동일, 단 1회성 emit

3. switches

subscriber가 어떤 sequence의 이벤트를 수신할지 결정

 

1) amb

- ambiguous(모호한) : 먼저 온 sequence만 구독

- server에서 대량의 데이터가 오는 경우 사용

example(of: "amb") {
  let left = PublishSubject<String>()
  let right = PublishSubject<String>()
  
  // 1
  let observable = left.amb(right)
  let disposable = observable.subscribe(onNext: { value in
    print(value)
  })
  
  // 2
  left.onNext("Lisbon")
  right.onNext("Copenhagen")
  left.onNext("London")
  left.onNext("Madrid")
  right.onNext("Vienna")
  
  left.onCompleted()
  right.onCompleted()
}

/* print
Lisbon
London
Madrid
*/

 

2) switchLatest

- emit할 시퀀스를 선택할 수 있게끔 함

 

// 1
let one = PublishSubject<String>()
let two = PublishSubject<String>()
let three = PublishSubject<String>()
let source = PublishSubject<Observable<String>>()

// 2
let observable = source.switchLatest()
let disposable = observable.subscribe(onNext: { value in
  print(value)
})

// 3
source.onNext(one)
one.onNext("Some text from sequence one")
two.onNext("Some text from sequence two")

source.onNext(two)
two.onNext("More text from sequence two")
one.onNext("and also from sequence one")

source.onNext(three)
two.onNext("Why don't you see me?")
one.onNext("I'm alone, help me")
three.onNext("Hey it's three. I win.")

source.onNext(one)
one.onNext("Nope. It's me, one!")

disposable.dispose()
}

/* prints
Some text from sequence one
More text from sequence two
Hey it's three. I win.
Nope. It's me, one!
*/

4. sequence내의 요소들간 결합

higher-order function에서의 reduce와 기능 동일

1) reduce(::)

 

- reduce(init, accumulator)

example(of: "reduce") {
    let source = Observable.of(1, 3, 5, 7, 9)

    // 1
    let observable = source.reduce(0, accumulator: +)
    observable.subscribe(onNext: { print($0) } )
}

(위와 동일한 코드)

// 2
let observable2 = source.reduce(0, accumulator: { summary, newValue in
    return summary + newValue
})
observable2.subscribe(onNext: { print($0) })

 

2) scan(_:accumulator:)

- reduce(::)와 같이 작동하지만 리턴값이 Observable이며 하나의 값으로 나오는게 아니고 누적되며 emit

 example(of: "scan") {
     let source = Observable.of(1, 3, 5, 7, 9)

     let observable = source.scan(0, accumulator: +)
     observable.subscribe(onNext: { print($0) })

     /* Prints:
      1
      4
      9
      16
      25
     */
 }

 

Comments