본문 바로가기

난 iOS개발자/Combine

Combine 변환연산자

728x90

Combine에서 우리는 퍼블리셔로부터 오는 값에 대한 연산을 수행하는 메소드를 " `operator` "라고 부릅니다.
각 결합 연산자는 게시자를 반환합니다. 일반적으로 게시자는 업스트림 이벤트를 수신하여 조작한 다음 조작된 이벤트 다운스트림을 소비자에게 보냅니다.

 

 

collect()

collect연산자의 publisher는 개별 값 스트림을 단일 배열로 변환하는 편리한 방법을 제공한다.
마블 다이어그램은 작업자가 작동하는 방식을 시각화하는 데 도움이 된다.
맨 윗줄은 업스트림 게시자,  상자는 연산자를 나타낸다. 그리고 마지막은 구독, 구체적으로는 업스트림 게시자로부터 오는 값을 조작한 후 구독자가 받게된다.

 

 

example(of: "collect") {
  ["A", "B", "C", "D", "E"].publisher
    .sink(receiveCompletion: { print($0) },
          receiveValue: { print($0) })
    .store(in: &subscriptions)
}

아직 콜렉트 연산자를 사용하지 않아서 아래와같이 출력될거다.

 

——— Example of: collect ———
A
B
C
D
E
finished

이제 콜렉트를 넣어주면

["A", "B", "C", "D", "E"].publisher
  .collect() //
  .sink(receiveCompletion: { print($0) },
        receiveValue: { print($0) })
  .store(in: &subscriptions)

 

아래와 같이 출력된다.

——— Example of: collect ———
["A", "B", "C", "D", "E"]
finished

 

매핑값

값을 수집하는것 외에도 이러한 값을 어떤 방식으로든 변환하려는 경우가 많다. 
Combine은 이를위해 여러 매핑 연산자를 제공한다.

 

map

 

example(of: "map") {
  // 1
  let formatter = NumberFormatter()
  formatter.numberStyle = .spellOut
  
  // 2
  [123, 4, 56].publisher
    // 3
    .map {
      formatter.string(for: NSNumber(integerLiteral: $0)) ?? ""
    }
    .sink(receiveValue: { print($0) })
    .store(in: &subscriptions)
}

출력결과 

——— Example of: map ———
one hundred twenty-three
four
fifty-six

 

tryMap

example(of: "tryMap") {
  // 1
  Just("Directory name that does not exist")
    // 2
    .tryMap { try FileManager.default.contentsOfDirectory(atPath: $0) }
    // 3
    .sink(receiveCompletion: { print($0) },
          receiveValue: { print($0) })
    .store(in: &subscriptions)
}

1. 존재하지 않는 디렉토리 이름을 나타내는 문자열의 게시자
2. `tryMap` 존재하지 않는 디렉토리 내용을 가져오기 위해 사용

——— Example of: tryMap ———
failure(..."The folder “Directory name that does not exist” doesn't exist."...)

 

 

 

Flattening Publisher

flatMap은 여러 업스트림 게시자를 단일 다운스트림 게시자로 `병합`하거나 해당 게시자의 배출량을 병합? 한다.

Combine의 일반적인 사용 사례는 한 게시자가 내보낸 요소를 자체 게시자를 반환하는 메서드에 전달하고 궁극적으로 두 번째 게시자가 내보낸 요소를 구독하려는 경우이다.  

example(of: "flatMap") {
  // 1
  func decode(_ codes: [Int]) -> AnyPublisher<String, Never> {
    // 2
    Just(
      codes
        .compactMap { code in
          guard (32...255).contains(code) else { return nil }
          return String(UnicodeScalar(code) ?? " ")
        }
        // 3
        .joined()
    )
    // 4
    .eraseToAnyPublisher()
  }
}

1. 각각 ASCII코드를 나타내는 정수 배열을 사용하고 오류를 발생시키지 않는 유형이 지워진 문자열 게시자를 반환하는 함수를 정의
2. 표준 및 확장 print가능한 ASCII문자를 포함하는 0.255범위 내에 있는 경우 문자 코드를 문자열로 변환하는 게시자 만듦.
3. 문자열을 함께 결합
4. 기능에 대한 반환 유형과 일치하도록 eraseToAnyPublisher()사용

 

// 5
[72, 101, 108, 108, 111, 44, 32, 87, 111, 114, 108, 100, 33]
  .publisher
  .collect()
  // 6
  .flatMap(decode)
  // 7
  .sink(receiveValue: { print($0) })
  .store(in: &subscriptions)
——— Example of: flatMap ———
Hello, World!

 

중요!

`flatMap`은 수신된 모든 게시자의 출력을 단일 게시자로 평면화 시킨다.
다운스트림에서 내보내는 단일 게시자를 업데이트하기 위해 보내는 만큼 많은 게시자를 버퍼링하므로 메모리 문제가 발생할 수 있다.

 

 

 

scan

업스트림 게시자가 내보낸 현재값을 해당 클로저에서 반환된 마지막 값과 함께 클로저에 제공합니다.

0인 값은 초기값을 말한다.
이후 1이 들어오고, 다음 2가 들어왔을때 이전에 들어온 1과 덧셈을 하여 3이 발생
이후 3이 들어올때, 이전에 발생한 3에 더하여 6이 발생했다

728x90

'난 iOS개발자 > Combine' 카테고리의 다른 글

eraseToAnyPublisher  (0) 2023.04.20
Combine01 개요  (0) 2022.10.17