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

Combine入門

 Combine入門

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

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