import UIKit
import Combine
import Foundation
var subscriptions = Set<AnyCancellable>()
func example(of name: String, closure: @escaping () -> Void) {
print("-------------------- \(name) --------------------")
closure()
}
example(of: "collection") {
// var subscriptions = Set<AnyCancellable>()
["A","B","C","D","E"].publisher
// .collect()
.collect(2)
.sink(receiveCompletion: {print($0)},
receiveValue: {print($0)})
.store(in: &subscriptions)
// publisher: Publishers.Sequence<[String], Never>
// : A Combine publisher that publishes each member of the sequence as a separate element.
// func collect() -> Result<[Publishers.Sequence<Elements, Failure>.Output], Failure>.Publisher
// .sink(receiveCompletion: <#T##((Subscribers.Completion<Never>) -> Void)##((Subscribers.Completion<Never>) -> Void)##(Subscribers.Completion<Never>) -> Void#>, receiveValue: <#T##((String) -> Void)##((String) -> Void)##(String) -> Void#>)
// Attaches a subscriber with closure-based behavior.
// .store(in: &<#T##Set<AnyCancellable>#>)
// Stores this type-erasing cancellable instance in the specified set
}
example(of: "map") {
// var subscriptions = Set<AnyCancellable>()
let formatter = NumberFormatter()
formatter.numberStyle = .spellOut // transform Number Into String
[123,4,56].publisher
.map {
formatter.string(for: NSNumber(integerLiteral: $0)) ?? ""
}
.sink(receiveValue: {print($0)})
.store(in: &subscriptions)
// .sink(receiveValue: <#T##((String) -> Void)##((String) -> Void)##(String) -> Void#>)
// Attaches a subscriber with closure-based behavior to a publisher that never fails.
}
func quadrantOf(x: Int, y: Int) -> String {
switch (x,y) {
case (x,y) where x > 0 && y > 0 : return "1"
case (x,y) where x < 0 && y > 0 : return "2"
case (x,y) where x < 0 && y < 0 : return "3"
case (x,y) where x > 0 && y < 0 : return "4"
default: return "boundary"
}
}
struct Coordinate {
let x: Int
let y: Int
}
example(of: "map key paths") {
// var subscriptions = Set<AnyCancellable>()
// 1 Create a publisher of Coordinates that will never emit an error
let publisher = PassthroughSubject<Coordinate, Never>()
// 2 Begin a subscription to the publisher
publisher
// 3 Map into the x and y properties of Coordinate using their key paths
.map(\.x, \.y)
.sink { x, y in
// 4 print a statement that indicates the quadrant of the provide x and y values
print("The coordinate at (\(x), \(y)) is in quadrant", quadrantOf(x: x, y: y))
}
.store(in: &subscriptions)
// 5 Send some coordinates through the publisher.
publisher.send(Coordinate(x: 10, y: -8))
publisher.send(Coordinate(x: 0, y: 5))
// .map(<#T##keyPath: KeyPath<Coordinate, T>##KeyPath<Coordinate, T>#>)
// publishes a value of key path
// publisher.send(<#T##input: Coordinate##Coordinate#>)
// send a value to the subscriber
// let publisher2 = PassthroughSubject<Int, Never>()
// PassthroughSubject: A subject that broadcasts elements to downstream subscribers
}
example(of: "tryMap") {
// var subscriptions = Set<AnyCancellable>()
// 1 Create a publisher of a string representing a directory name that does not exist
Just("Directory name that does not exist")
// 2. Use trymap to attempt to get the contents of the nonexistent directory.
.tryMap { try
FileManager.default.contentsOfDirectory(atPath: $0)}
// 3. Receive and print out any values or completion events.
.sink(receiveCompletion: {print($0)}, receiveValue: {print($0)})
.store(in: &subscriptions)
// A publisher that emits an output to each subscriber just once, and then finishes
// Just(<#T##output: _##_#>)
// initializes a publisher that emits the specified output just once
// .tryMap(<#T##transform: (String) throws -> T##(String) throws -> T#>)
// Transforms all elements from the upstream publisher with a provided error-throwing closure.
}
public struct Chatter {
public let name: String
public let message: CurrentValueSubject<String, Never>
public init(name: String, message: String) {
self.name = name
self.message = CurrentValueSubject(message)
// CurrentValueSubject: A subject that wraps a single value and publishes a new element whenever the value changes
}
}
example(of: "flatMap") {
// 1 Create two instances of Chatter: charlotte and james
let charlotte = Chatter(name: "Charlotte", message: "Hi, I'm Charlotte!")
let james = Chatter(name: "James", message: "Hi, I'm James!")
// 2 Create a chat publisher initialized with charlotte
let chat = CurrentValueSubject<Chatter, Never>(charlotte)
// 3 Subscribe to chat and print out the message of any received Chatter structure.
chat
// 6. flatmap into the Chatter structure message publisher.
// .flatMap{ $0.message }
.flatMap(maxPublishers: .max(2)) { $0.message }
// .sink(receiveValue: {print($0.message.value)})
// 7. Change the handler to print the vlaue received, which is now a string, not a Chatter instance.
.sink(receiveValue: {print($0)})
.store(in: &subscriptions)
// 4 Change Charlotte's message
charlotte.message.value = "Charlotte: How's it going?"
// 5 Change the chat publisher's current value to james.
chat.value = james
james.message.value = "James: Doing great. You?"
charlotte.message.value = "Charlotte: I'm doing fine thanks."
// 8 Create a third Chatter instance.
let morgan = Chatter(name: "Morgan",
message: "Hey guys, what are you up to?")
// 9 Add that Chatter onto the chat publisher.
chat.value = morgan
// 10 Change Charlotte’s message.
charlotte.message.value = "Did you hear something?"
}
example(of: "replaceNil") {
// var subscriptions = Set<AnyCancellable>()
["A", nil, "C"].publisher
.replaceNil(with: "-")
.map{$0!}
.sink(receiveValue: {print($0)})
.store(in: &subscriptions)
}
example(of: "replaceEmpty(with:)") {
// 1. Create an empty publisher that immediately emits a completion event.
let empty = Empty<Int, Never>()
// 2. Subscribe to it, and print received events.
empty
.replaceEmpty(with: 1)
// replaces empty stream with the provided element
// .replace
.sink(receiveCompletion: {print($0)},
receiveValue: {print($0)})
.store(in: &subscriptions)
}
example(of: "scan") {
// 1
var dailyGainLoss: Int {.random(in: -10 ... 10)}
var count = 0
// 2
let august2021 = (0 ..< 22)
.map { _ in dailyGainLoss }
.publisher
august2021
.scan(50) { latest, current in
max(0, latest + current)
}
.sink(receiveValue: {
// print(count + $0)
count += 1
print("\(count) : \($0)")
})
.store(in: &subscriptions)
}