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

Combine入門

Sponsored · Ship Features Fearlessly Turn features on and off without deploys. Used by thousands of Ruby developers.

 Combine入門

AppleのCombineフレームワークの基本的な内容について

Avatar for shtnkgm

shtnkgm

June 11, 2020
Tweet

More Decks by shtnkgm

Other Decks in Programming

Transcript

  1. UIKitͷඇಉظॲཧ • Taregt/ActionʢTimer, @IBAction ...ʣ • NotificationCenter • URLSession •

    KVOʢKey-value observingʣ • Callback࣮૷ʢDelegate, Closureʣ 3
  2. Publisherͷఆٛ protocol Publisher { associatedtype Output associatedtype Failure: Error //

    Subscriberͷొ࿥ func subscribe<S>(_ subscriber: S) where S : Subscriber, Self.Failure == S.Failure, Self.Output == S.Input } 8
  3. NotificationCenterͰͷPublisher࣮૷ྫ extension NotificationCenter { struct Publisher: Combine.Publisher { typealias Output

    = Notifiation typealias Failure = Never // Τϥʔͳ͍৔߹͸Neverܕ init(center: NotificationCenter, name: Notification.Name, object: Any? = nil) } } 9
  4. fatalErrorͷ໭Γ஋΋Neverܕ class ViewController: UIViewController init() { ... } required init?(coder

    aDecoder: NSCoder) { // NeverܕΛฦ͢͜ͱͰϓϩάϥϜऴྃ fatalError("init(coder:) has not been implemented") } func hoge() -> Int { // ໭Γ஋ͷܕݕࠪ΋ߦΘΕͳ͍ͷͰ // ͜ΕͰίϯύΠϧ͕௨Δ fatalError() } } 13
  5. Subscriberͷఆٛ protocol Subscriber { associatedtype Input associatedtype Failure : Error

    // SubscriptionΛड͚औΔ func receive(subscription: Subscription) // ೖྗ஋Λड͚औΔ func receive(_ input: Self.Input) -> Subscribers.Demand // ׬ྃΛड͚औΔʢ༗ݶͷ৔߹ʣ func receive(completion: Subscribers.Completion<Self.Failure>) } 15
  6. Subscriberͷ࣮૷ྫʢAssignʣ ࢦఆ͞ΕͨΩʔύεʹ஋Ληοτ͢ΔSubscriber // Subscribers͸ͨͩͷnamespaceͱͯ͠ͷenum // AssignͷଞʹɺDemand, Completion, Sink͕͋Δ extension Subscribers

    { class Assign<Root, Input>: Subscriber, Cancellable { typealias Faiure = Never init(object: Root, keyPath: ReferenceWritableKeyPath<Root, Input>) } } 16
  7. Operatorͷ࣮૷ྫʢMapʣ // ͜Ε΋namespace // MapҎ֎ʹ΋Sequence, Catch, ReceiveOn, SubscribeOn...ͳͲΊͬͪΌ͋Δ extension Publishers

    { struct Map<Upstream, Output> where Upstream : Publisher { typealias Failure = Upstream.Failure let upstream: Upstream let transform: (Upstream.Output) -> Output } } 18
  8. Publisher, Subscriber, OperatorΛ࢖ͬͯΈΔ ຐ๏ֶߍͱֶ೥ class Wizard { var grade: Int

    init(grade: Int) { self.grade = grade } } let merlin = Wizard(grade: 5) 20
  9. Publisher, Subscriber, OperatorΛ࢖ͬͯΈΔ let graduationPublisher = NotificationCenter.Publisher(center: .default, name: .graduated,

    object: merlin) let gradeSubscriber = Subscribers.Assign(object: merlin, keyPath: \.grade) let converter = Publishers.Map(upstream: graduationPublisher) { note in return note.userInfo?["NewGrade"] as? Int ?? 0 } converter.subscribe(gradeSubscriber) 21
  10. Publisherͷmap, assign֦ு extension Publisher { func map<T>(_ transform: @escaping (Self.Output)

    -> T) -> Publishers.Map<Self, T> { return Publishers.Map(upstream: self, transform: transform) } } extension Publisher where Self.Failure == Never { func assign<Root>(to keyPath: ReferenceWritableKeyPath<Root, Self.Output>, on object: Root) -> AnyCancellable { return Subscribers.Assign<Self, Input>(object: object, keyPath: keyPath) } } 22
  11. ϝιουνΣΠϯͰΑΓએݴతʹ let cancellable = NotificationCenter.default.publisher(for: .graduated, object: merlin) .map {

    note in return note.userInfo?["NewGrade"] as? Int ?? 0 } .assign(to: \.grade, on: merlin) 23
  12. ௨৴ॲཧʹ࢖͑ͦ͏ͳ΋ͷ΋ଟ͍ https://developer.apple.com/documentation/combine/publishers • Zip, Zip3, Zip4, CombineLatest: ଴ͪ߹Θͤ • Decode:

    σίʔυॲཧ • Retry: ϦτϥΠ • Throttle, Debounce: ࿈ଓ͢ΔΠϕϯτΛݮΒ͢ʢ࿈ଧɺΠϯΫϦϝϯλϧαʔ νʣ • Timeout: λΠϜΞ΢τ 25
  13. class UserRepository { private var subscriptions = Set<AnyCancellable>() func fetchUsers()

    -> Future<[User], UserAPIError> { return Future<[User], UserAPIError> { [unowned self] promise in URLSession .shared .dataTaskPublisher(for: url) .debounce(for: .milliseconds(500), scheduler: RunLoop.main) .retry(3) .map { $0.data } .decode(type: [User].self, decoder: JSONDecoder()) .receive(on: DispatchQueue.main) .sink(receiveCompletion: { _ in promise(.failure(.somethingWrong)) }, receiveValue: { users in promise(.success(users)) }) .store(in: &self.subscriptions) } } func cancelAll() { subscriptions.forEach { $0.cancel() } } } 27
  14. noppefoxwolf/Combinative • https://github.com/noppefoxwolf/Combinative • UIKitͷUIControllʹCombineΛ֦ு let button = UIButton() button.cmb.tap.sink

    { (button) in // do something } @IBOutlet weak var textField: UITextField! textField.cmb.text.sink { (text) in print(text) } 29