ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Combine Operators 1 (transforming)
    IOS/Combine 2024. 4. 13. 15:23

    Operator

    Combine을 영어로 비교하자면 Operator는 단어 같은 존재입니다.

    Combine사용 시 필수적으로 사용되며, 다양한 연산을 맡아 처리하고 다시 방출하는 메커니즘을 가지고 있습니다.

    이런 Operator를 가지고 방출된 값을 Collect해 배열로 합쳐 subscriber에게 전달하거나, 예외처리 같은 작업도 가능합니다.

    따라서 Operators를 Upstream Publisher를 재가공한 다른 형태의 Publisher라 이해하면 좋을 거 같습니다.

     

    Combine에서 여러가지 Operator가 존재합니다.

     

    1. collect()

    Publisher가 방출하는 값들을 Single Array로 묶어서 다시 방출하는 연산자입니다.

    Upstream Publisher가 종료될 때까지 기다리기 때문에 메모리를 계속 사용하고 있어 런타임 에러가 발생할 수 있습니다.

    따라서 Count(count:Int)메소드로 제한을 걸어주거나, Count(:_,:options)를 사용해 특정 조건에 만족할 때까지만 수집하는 방법으로 오류를 줄일 수 있습니다.

     

    더보기

    예제코드

     

    ["A", "B", "C", "D", "E"].publisher
        .collect()
        .sink(receiveCompletion: { print($0) },
              receiveValue: { print($0) })
    //    output: ["A", "B", "C", "D", "E"]
    //            finished
    
    ["A", "B", "C", "D", "E"].publisher
        .collect(2)
        .sink(receiveCompletion: { print($0) },
              receiveValue: { print($0) })
    //     output :["A", "B"]
    //             ["C", "D"]
    //             ["E"]
    //             finished

     

    2. map과 compactMap()

    Swift에서 사용하는 map, CompatMap method와 비슷한 역할을 하는 Operator로, Upstream Publisher가 방출한 Value를 다른 형태의 Value로 다시 Map 해 방출하는 Operator입니다. Combine학습할 정도의 수준이면 map, compactMap은 잘 아실 거 같아 바로 예제 코드로 설명드리겠습니다.

    더보기

    예제코드

     

    [123, 4, 56].publisher
        .map { $0 * 2 }
        .sink(receiveValue: { print($0) })
    // Output: 246
    //         8
    //         112
    
    
    let arr = ["1", "abc", "56"]
    arr.publisher
        .compactMap { Int($0) }
        .sink(receiveValue: { print($0) })
    // Output: 1
    //         56

     

    3. tryMap(_:)

    Combine에서 try 접두사가 붙은 Operator는 보통 에러 가능성이 있는 작업을 수행하고 에러 발생 시 publisher는 Subscriber에게 failure를 방출하게 됩니다. 

     

    다음 코드는 Apple Document에 있는 예제 코드입니다.

    더보기

    예제코드

     

    func romanNumeral(from:Int) throws -> String {
        let romanNumeralDict: [Int : String] =
            [1:"I", 2:"II", 3:"III", 4:"IV", 5:"V"]
        guard let numeral = romanNumeralDict[from] else {
            throw ParseError()
        }
        return numeral
    }
    let numbers = [5, 4, 3, 2, 1, 0]
    cancellable = numbers.publisher
        .tryMap { try romanNumeral(from: $0) }
        .sink(
            receiveCompletion: { print ("completion: \($0)") },
            receiveValue: { print ("\($0)", terminator: " ") }
         )
    
    
    // Prints: "V IV III II I completion: failure(ParseError())"

    예제 코드를 보면, romanNumeral 메소드를 호출해 각 숫자에 맞는 로마 숫자를 변환하고 있습니다.
    0의 경우 해당하는 로마 숫자가 없기 때문에 ParseError를 Throw 하게 되며, subscriber에선 failure를 수신하게 되는 예제입니다.

     If the closure throws an error, the publisher fails with the thrown error

    4. flatMap(maxPublishers:_:)

    저희가 아는 Foundation의 FlatMap과 달리 2차원 배열을 1차원 배열로 변환하는 것이 아닌 여러 개의 upstream publisher 들을 Signle downstream publisher로 만드는 데 목적이 있는 Operator입니다.

     

    더보기

    예제코드

     

    func fetchUserName(id: Int) -> AnyPublisher<String, Never> {
        let names = ["Alice", "Bob", "Charlie"]
        let index = id % names.count
        return Just(names[index])
            .delay(for: .seconds(1), scheduler: DispatchQueue.main)
            .eraseToAnyPublisher()
    }
    
    let userIds = [1, 2, 3]
    
    let cancellable = userIds.publisher
        .flatMap { id in
            fetchUserName(id: id)
        }
        .sink(receiveValue: { name in
            print("Fetched user name: \(name)")
        })
    
    // Output: Fetched user name: Bob
    //         Fetched user name: Charlie
    //         Fetched user name: Alice

     

     그림으로 이해하기

    해당 그림에서 P1, P2, P3는 FlatMap 메소드 클로저 내에서 생성하는 Just Publisher입니다. 이런 각기 다른 Publisher를 FlatMap을 통해 하나의 스트림으로 묶은 그림이며, 이렇게 묶인 스트림에서 데이터 방출시에도 하나의 스트림에서 방출 된다는 것을 시각적으로 간단하게 표현했습니다.

     

     

    'IOS > Combine' 카테고리의 다른 글

    Combine Operators 2(Replace)  (1) 2024.04.21
    Combine Cancellable, subscription  (0) 2024.04.07
    Combine - Subscriber 2편  (0) 2024.03.30
    Combine - Subscriber 1편  (0) 2024.03.16
    Combine 구성요소 Publisher  (0) 2024.03.10
Designed by Tistory.