Publisher umwandeln mit Operatoren - wurzelsand/swift-memos GitHub Wiki

Publisher umwandeln mit Operatoren

Themen

  • collect()
  • map()
  • flatMap()
  • tryMap()
  • scan()
  • Just-Publisher
  • if case let
  • throws

Aufgabe 1: Collect

Schicke aus einer Schleife die Zahlen von 0 bis 9 über ein PassthroughSubject an ein Sink und gebe sie als Array aus.

Ausführung

import Combine

var subscriptions = Set<AnyCancellable>()

let subject = PassthroughSubject<Int, Never>()

subject
    .collect()
    .sink(receiveCompletion: { print("completion:", $0)}, receiveValue: { print("value:", $0)})
    .store(in: &subscriptions)

for i in 0..<10 {
    subject.send(i)
}
subject.send(completion: .finished)

Ausgabe:

value: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
completion: finished
Program ended with exit code: 0

Anmerkungen

  • Mit collect(3) würden immer nur maximal 3 Werte zwischengespeichert und dementsprechend mehrere Arrays aus maximal 3 Werten verschickt.

Aufgabe 2: map

Gegeben sei ein Publisher von Strings:

["hello", "world"].publisher

Wandel den gegebenen Publisher in einen Publisher um, der alle Buchstaben in Großbuchstaben umwandelt.

Ausführung

var subscriptions = Set<AnyCancellable>()

func uppercased(of string: String) -> String {
    string.uppercased()
}

["hello", "world"].publisher
    .map(uppercased(of:))
    .sink {
        print("value:", $0)
    }
    .store(in: &subscriptions)
    
}

Ausgabe:

value: HELLO
value: WORLD

Aufgabe 3: flatMap

Gegeben sei ein Publisher von Strings:

["hello", "world"].publisher

Wandel den gegebenen Publisher in mehrere Publisher um, die Buchstaben in Großbuchstaben umwandeln.

Ausführung

var subscriptions = Set<AnyCancellable>()

func uppercased(of string: String) -> AnyPublisher<String, Never> {
    Just(string.uppercased())
        .eraseToAnyPublisher()
}

["hello", "world"].publisher
    .flatMap(maxPublishers: .unlimited, uppercased(of:))
    .sink {
        print("value:", $0)
    }
    .store(in: &subscriptions)

}

Ausgabe:

value: HELLO
value: WORLD

Anmerkungen

map erzeugt einen Publisher der die einzelnen Elemente des Datenstroms umwandelt. flatMap erzeugt aus den einzelnen Elementen des Datenstroms mehrere Publisher.

Aufgabe 4: TryMap

Wir erweitern String um eine Methode isCapitalized die einen StringError auslösen kann:

enum StringError: Error {
    case empty
}

extension String {
    func isCapitalized() throws -> Bool {
        guard let first = first else { throw StringError.empty }
        return first.isUppercase
    }
}

Ein Just-Publisher für Strings soll von einem Sink abonniert werden, der ausgibt, ob der String groß geschrieben wurde. Wenn ein StringError ausgelöst wurde, soll er im Completion-Block angezeigt werden.

Ausführung

enum StringError: Error {
    case empty
}

extension String {
    func isCapitalized() throws -> Bool {
        guard let first = first else { throw StringError.empty }
        return first.isUppercase
    }
}

var subscriptions = Set<AnyCancellable>()

Just("")
    .tryMap {
        try $0.isCapitalized()
    }
    .sink(receiveCompletion: { completion in
        if case let .failure(error) = completion {
            if case StringError.empty = error {
                print("String is empty")
            }
        }
    }, receiveValue: { print("capitalized:", $0) })
    .store(in: &subscriptions)

Ausgabe:

String is empty

Aufgabe 5: Scan

Gegeben sei ein Publisher:

["H", "e", "l", "l", "o"].publisher

Ausgegeben werden soll:

H
He
Hel
Hell
Hello

Ausführung

var subscriptions = Set<AnyCancellable>()

["H", "e", "l", "l", "o"].publisher
    .scan("") { stored, new in // .scan("", +)
        return stored + new
    }
    .sink {
        print($0)
    }
    .store(in: &subscriptions)
⚠️ **GitHub.com Fallback** ⚠️