Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Combine Overview

d_date
August 05, 2019

Combine Overview

2019/08/05 Combineゴリゴリキャッチアップ会

d_date

August 05, 2019
Tweet

More Decks by d_date

Other Decks in Programming

Transcript

  1. Daiki Matsudate • Tokyo, Japan • iOS Developer from iOS

    4 • Independent Developer • @d_date • Sushi
  2. Why Reactive Programing? • ෳ਺ͷඇಉظ (Asynchronous) ͳλεΫΛͲ͏ѻ͏͔ • Ͳ͏ѻ͏͔ •

    Ͳͷॱ൪Ͱʁ • ௚ྻ / ฒྻ? • ్தͰΤϥʔ͕ൃੜͨ͠Βʁ
  3. public protocol Publisher { /// The kind of values published

    by this publisher. associatedtype Output /// The kind of errors this publisher might publish. /// Use `Never` if this `Publisher` does not publish errors. associatedtype Failure : Error /// This function is called to attach the specified `Subscriber` to this `Publisher` by `subscribe(_:)` func receive<S>(subscriber: S) where S : Subscriber, Self.Failure == S.Failure, Self.Output == S.Input } Publisher
  4. @Published @propertyWrapper public struct Published<Value> { /// Initialize the storage

    of the Published property as well as the corresponding `Publisher`. public init(initialValue: Value) public class Publisher : Publisher { /// The kind of values published by this publisher. public typealias Output = Value /// The kind of errors this publisher might publish. /// /// Use `Never` if this `Publisher` does not publish errors. public typealias Failure = Never /// This function is called to attach the specified `Subscriber` to this `Publisher` by `subscribe(_:)` public func receive<S>(subscriber: S) where Value == S.Input, S : Subscriber, S.Failure == Published<Value>.Publisher.Failure } /// The property that can be accessed with the `$` syntax and allows access to the `Publisher` public var projectedValue: Published<Value>.Publisher { mutating get } }
  5. Default Publishers • Notification Center • URLSession • Just, Future

    • CurrentValueSubject, PassthroughSubject • NSManagedObject let ncpublisher = NotificationCenter.Publisher(center: .default, name: .NSCalendarDayChanged) let sessionPublisher = URLSession(configuration: .default) .dataTaskPublisher(for: URL(string: “https://api.google.com")!) let managedObject = NSManagedObject(context: context).publisher(for: \.hasChanges) let just = Just<String>("") let future = Future<String, Error> { (result) in result(.success("result")) result(.failure(TypedError.example)) }
  6. public protocol Subscriber : CustomCombineIdentifierConvertible { /// The kind of

    values this subscriber receives. associatedtype Input /// The kind of errors this subscriber might receive. /// Use `Never` if this `Subscriber` cannot receive errors. associatedtype Failure : Error /// Tells the subscriber that it has successfully subscribed to the publisher and may request items. /// /// Use the received `Subscription` to request items from the publisher. func receive(subscription: Subscription) /// Tells the subscriber that the publisher has produced an element. func receive(_ input: Self.Input) -> Subscribers.Demand /// Tells the subscriber that the publisher has completed publishing, either normally or with an error. func receive(completion: Subscribers.Completion<Self.Failure>) } Subscriber
  7. let labelTextSubscriber = Subscribers.Assign(object: label, keyPath: \.text) $queryPublisher .map {

    "searching for \($0)..." } .map(Optional.init) .subscribe(labelTextSubscriber) labelTextSubscriber.cancel() Assign
  8. let cancellable = $queryPublisher .map { "searching for \($0)..." }

    .assign(to: \.text, on: label) // how to cancel cancellable.cancel() Assign
  9. var cancellables = [AnyCancellable]() $queryPublisher .map { "searching for \($0)..."

    } .assign(to: \.text, on: label) .store(in: &cancellables) Assign
  10. let labelTextSubscriber = Subscribers.Sink<String?, Never>(receiveCompletion: { _ in }) {

    self.label.text = $0 } $queryPublisher .map { "searching for \($0)..." } .subscribe(labelTextSubscriber) labelTextSubscriber.cancel() Sink
  11. let cancellable = $queryPublisher .map { "searching for \($0)..." }

    .sink { self.label.text = $0 } cancellable.cancel() Sink
  12. var cancellables = [AnyCancellable]() $queryPublisher .map { "searching for \($0)..."

    } .sink { self.label.text = $0 } .store(in: &cancellables) Sink
  13. subscribe(on:) vs. receive(on:) • subscribe(on:) ͸ upstream messagesʹӨڹ • receive(on:)

    ͸downstream messagesͷ࣮ߦίϯςΩετʹӨڹ • ͜ͷྫͰ͸ɺpublisher΁ͷϦΫΤετ͸backgroundQueueͰߦΘΕΔ ͕ɺΤϨϝϯτΛड͚औΔͷ͸ϝΠϯεϨου let backgroundQueue = DispatchQueue(label: "background", qos: .utility) $queryPublisher .map { "searching for \($0)..." } .subscribe(on: backgroundQueue) .receive(on: DispatchQueue.main) .sink { self.label.text = $0 } .store(in: &cancellables)
  14. The Pattern Subscriber is attached to Publisher Publisher sends a

    Subscription Subscriber requests N values Publisher sends N values or less Publisher sends completion Publisher Subscriber subscribe( ) receive(subscription:) request(_ : Demand) receive(completion:) receive(_ : Input) receive(_ : Input) • • •
  15. // Combine with SwiftUI class WizardModel : BindableObject { var

    trick: WizardTrick { didSet { didChange.send() } var wand: Wand? { didSet { didChange.send() } let didChange = PassthroughSubject<Void, Never>() } struct TrickView: View { @ObjectBinding var model: WizardModel var body: some View { Text(model.trick.name) } }
  16. catch abortOnError allSatisfy append breakpoint breakpointOnError combineLatest compactMap count dropFirst

    filter first handleEvents ignoreOutput last log mapError max min output prefix prepend print removeDuplicates replaceEmpty replaceError replaceNil retry scan setFailureType switchToLatest zip map contains flatMap reduce merge drop collect From WWDC19 Introducing Combine