iOS

Combine - Operator(switchToLastest, FlatMap)

728x90

Operator

: Publisher가 subcriber에게 전달하는 데이터를 변환하는 작업을 중간에 할 수가 있음.

오늘 살펴볼 목록

  • switchToLastest
  • flatMap
  • subscribe
  • receive
  • map(\.data)
  • flatMap
  • scan
  • removeDuplicates

switchToLastest

  • 요청중인 작업을 취소하고, 현재 구독으로 바꿔버리는 작업을 해줌
  • 예를 들어 네트워크 요청을 하고 있을 때, publisher가 다른 내용을 전달 했다면 그 즉시 새로운 publisher를 구독함으로, 기존의 publisher의 구독을 취소하고 새로운 publisher을 구독한다는 것임.
  • 즉, 네트워크 통신 중 이였다면 취소하고, 새롭게 요청한 네트워크 요청으로 바꿔버린다는 것임.
let subject = PassthroughSubject<int, never="">()
cancellable = subject
    .setFailureType(to: URLError.self)
    .map() { index -> URLSession.DataTaskPublisher in
        let url = URL(string: "<https://example.org/get?index=\\(index)>")!
        return URLSession.shared.dataTaskPublisher(for: url)
    }
    .switchToLatest()
    .sink(receiveCompletion: { print("Complete: \\($0)") },
          receiveValue: { (data, response) in
            guard let url = response.url else { print("Bad response."); return }
            print("URL: \\(url)")
    })

for index in 1...5 {
    DispatchQueue.main.asyncAfter(deadline: .now() + TimeInterval(index/10)) {
        subject.send(index)
    }
}

// Prints "URL: <https://example.org/get?index=5>"
</int,>

subscribe(on: queue)

  • .subscribe(on: queue) : publisher를 구독하여 값을 받고, 로직을 동작 시킬 때 어느 quque에서 동작 시킬 건지 정해줄수있음. 가장 최상위에 작성된 .subscribe에 따라 동작함.
let ioPerformingPublisher == // Some publisher.
let uiUpdatingSubscriber == // Some subscriber that updates the UI.

ioPerformingPublisher
    .subscribe(on: backgroundQueue)
    .receive(on: RunLoop.main)
    .subscribe(uiUpdatingSubscriber)

receive(on:queue)

  • receive(on:queue): operator, subscriber에서의 행위를 각각 어떤 큐에서 동작 시킬 수 정해줄수 있음.!
let jsonPublisher = MyJSONLoaderPublisher() // Some publisher.
let labelUpdater = MyLabelUpdateSubscriber() // Some subscriber that updates the UI.

jsonPublisher
    .subscribe(on: backgroundQueue)
    .receive(on: RunLoop.main)
    .subscribe(labelUpdater)

pub.sink {
    DispatchQueue.main.async {
        // Do something.
    }
}
// 대신 다음 패턴을 사용하세요.
pub.receive(on: DispatchQueue.main).sink {
    // Do something.
}

FlatMap

  • FlatMap: 동시성을 제어할 수가 있다. 안에 돌아갈 publisher 프로세스의 갯수를 제한 할 수 있다.
public struct WeatherStation {
    public let stationID: String
}

var weatherPublisher = PassthroughSubject<weatherstation, urlerror="">()

cancellable = weatherPublisher.flatMap { station -> URLSession.DataTaskPublisher in
    let url = URL(string:"<https://weatherapi.example.com/stations/\\(station.stationID)/observations/latest>")!
    return URLSession.shared.dataTaskPublisher(for: url)
}
.sink(
    receiveCompletion: { completion in
        // Handle publisher completion (normal or error).
    },
    receiveValue: {
        // Process the received data.
    }
 )

weatherPublisher.send(WeatherStation(stationID: "KSFO")) // San Francisco, CA
weatherPublisher.send(WeatherStation(stationID: "EGLC")) // London, UK
weatherPublisher.send(WeatherStation(stationID: "ZBBB")) // Beijing, CN
</weatherstation,>

Scan

  • scan: reduce와 비슷함. publisher를 초기값 + 다음 값 해서 넘겨주는 형식인듯
let range = (0...5)
cancellable = range.publisher
    .scan(0) { return $0 + $1 }
    .sink { print ("\\($0)", terminator: " ") }
 // Prints: "0 1 3 6 10 15 ".

catch

catch: 에러 핸들링

  • Empty(): publisher종류 중 하나, 값을 게시하지 않고 선택적으로 즉시 완료되는 Publisher 입니다.
struct SimpleError: Error {}
let numbers = [5, 4, 3, 2, 1, 0, 9, 8, 7, 6]
cancellable = numbers.publisher
    .tryLast(where: {
        guard $0 != 0 else {throw SimpleError()}
        return true
    })
    .catch({ (error) in
        Just(-1)
    })
    .sink { print("\\($0)") }
    // Prints: -1

removeDuplicates

  • removeDuplicates
    • 중복제거가 아니라, 이전과 비교해서 같은 경우 제거한다.
let numbers = [0, 1, 2, 2, 3, 3, 3, 4, 4, 4, 4, 0]
cancellable = numbers.publisher
    .removeDuplicates()
    .sink { print("\\($0)", terminator: " ") }

// Prints: "0 1 2 3 4 0"
반응형