Dimitri James Tsiflitzis
CocoaheadsSKG
Network requests.
UI
Publisher exposes values that can change, on which a subscriber subscribes to receive all those updates.
Combine = Publishers + Subscribers + OperatorsPublishers sends sequences of values over time to one or more Subscribers.
protocol Publisher {
associatedtype Output
associatedtype Failure : Error
func receive<S>(subscriber: S) where S : Subscriber,
Self.Failure == S.Failure,
Self.Output == S.Input
}A publisher can send values or terminate with either success or error.
Subscriber receives values from a publisher.
public protocol Subscriber : CustomCombineIdentifierConvertible {
associatedtype Input
associatedtype Failure : Error
func receive(subscription: Subscription)
func receive(_ input: Self.Input) -> Subscribers.Demand
func receive(completion: Subscribers.Completion<Self.Failure>)
}A subscriber can receive a value of type Input or a termination event with either success or Failure .
[1, 2, 3]
.publisher
.sink(receiveCompletion: { completion in
switch completion {
case .failure(let error):
print("Something went wrong: \(error)")
case .finished:
print("Received Completion")
}
}, receiveValue: { value in
print("Received value \(value)")
})var subscription: AnyCancellable?
func subscribe() {
let notification = UIApplication.keyboardDidShowNotification
let publisher = NotificationCenter.default.publisher(for: notification)
subscription = publisher.sink(receiveCompletion: { _ in
print("Completion")
}, receiveValue: { notification in
print("Received notification: \(notification)")
})
}
subscribe()
NotificationCenter.default.post(Notification(name: UIApplication.keyboardDidShowNotification))// start manually
let timerPublisher = Timer.publish(every: 1.0, on: RunLoop.main, in: .default)
cancellable = timerPublisher
.sink {
print($0)
}
// start publishing time
let cancellableTimerPublisher = timerPublisher.connect()
// stop publishing time
//cancellableTimerPublisher.cancel()
// cancel subscription
//cancellable?.cancel()subscription?.cancel()
NotificationCenter
.default
.post(Notification(name: UIApplication.keyboardDidShowNotification))let publisher = NotificationCenter.default
.publisher(for: notification)
.map { (notification) -> CGFloat in
guard let endFrame = notification
.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue
else {
return 0.0
}
return endFrame.cgRectValue.height
}
Subject is a special kind of Publisher that can insert values, passed from the outside, into the stream. Subject’s interface provides three different ways of sending elements:
public protocol Subject : AnyObject, Publisher {
func send(_ value: Self.Output)
func send(completion: Subscribers.Completion<Self.Failure>)
func send(subscription: Subscription)
}Combine has two built-in subjects: PassthroughSubject and CurrentValueSubject.
// 1
let subject = PassthroughSubject<String, Never>()
// 2
subject.sink(receiveCompletion: { _ in
print("finished")
}, receiveValue: { value in
print(value)
})
// 3
subject.send("Hello,")
subject.send("World!")
subject.send(completion: .finished) // 4Hello,
World!
finishedCurrentValueSubject starts with an initial value and publishes all it’s changes. It can return it’s current value via the value property.
// 1
let subject = CurrentValueSubject<Int, Never>(1)
// 2
print(subject.value)
// 3
subject.send(2)
print(subject.value)
// 4
subject.sink { value in
print(value)
}1
2
2This keyword is a property wrapper and adds a Publisher to any property.
final class FormViewController: UIViewController {
@Published var isSubmitAllowed: Bool = false
@IBOutlet private weak var acceptTermsSwitch: UISwitch!
@IBOutlet private weak var submitButton: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
$isSubmitAllowed
.receive(on: DispatchQueue.main)
.assign(to: \.isEnabled, on: submitButton)
}
@IBAction func didSwitch(_ sender: UISwitch) {
isSubmitAllowed = sender.isOn
}
}