Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Combine入門
Search
shtnkgm
June 11, 2020
Programming
2
290
Combine入門
AppleのCombineフレームワークの基本的な内容について
shtnkgm
June 11, 2020
Tweet
Share
More Decks by shtnkgm
See All by shtnkgm
Property Wrappers
shtnkgm
0
340
Saliency Detection
shtnkgm
0
48
パフォーマンス改善とユニットテスト
shtnkgm
4
1.6k
iOSのコードベースレイアウト
shtnkgm
2
770
20190117_iOSLT_CBLinSwift.pdf
shtnkgm
0
92
SwiftとFunctional Reactive Programming
shtnkgm
0
170
20180710_iOSLT_iOSでDarkModeを実装する
shtnkgm
0
91
20180410_iOSLT_SwiftとProtocol-OrientedProgramming
shtnkgm
0
110
20180220_iOSLT_Swiftとオブジェクト間の通知のパターン
shtnkgm
0
130
Other Decks in Programming
See All in Programming
AWS発のAIエディタKiroを使ってみた
iriikeita
1
190
Oracle Database Technology Night 92 Database Connection control FAN-AC
oracle4engineer
PRO
1
460
GitHubとGitLabとAWS CodePipelineでCI/CDを組み比べてみた
satoshi256kbyte
4
240
アセットのコンパイルについて
ojun9
0
130
詳解!defer panic recover のしくみ / Understanding defer, panic, and recover
convto
0
240
Performance for Conversion! 分散トレーシングでボトルネックを 特定せよ
inetand
0
1.9k
The Past, Present, and Future of Enterprise Java
ivargrimstad
0
390
🔨 小さなビルドシステムを作る
momeemt
4
680
Ruby Parser progress report 2025
yui_knk
1
450
RDoc meets YARD
okuramasafumi
4
170
意外と簡単!?フロントエンドでパスキー認証を実現する WebAuthn
teamlab
PRO
2
770
もうちょっといいRubyプロファイラを作りたい (2025)
osyoyu
1
450
Featured
See All Featured
Building Better People: How to give real-time feedback that sticks.
wjessup
368
19k
ピンチをチャンスに:未来をつくるプロダクトロードマップ #pmconf2020
aki_iinuma
127
53k
Music & Morning Musume
bryan
46
6.8k
Making the Leap to Tech Lead
cromwellryan
135
9.5k
Refactoring Trust on Your Teams (GOTO; Chicago 2020)
rmw
35
3.1k
Intergalactic Javascript Robots from Outer Space
tanoku
272
27k
Six Lessons from altMBA
skipperchong
28
4k
RailsConf 2023
tenderlove
30
1.2k
Making Projects Easy
brettharned
117
6.4k
Raft: Consensus for Rubyists
vanstee
140
7.1k
For a Future-Friendly Web
brad_frost
180
9.9k
The Invisible Side of Design
smashingmag
301
51k
Transcript
! Combineೖ 2020.6.11 iOSLT / @shtnkgm 1
Combineͱ • Swift͚Framework • WWDC2019Ͱൃද • iOS 13.0+ • ඇಉظॲཧΛѻ͏ͷ
2
UIKitͷඇಉظॲཧ • Taregt/ActionʢTimer, @IBAction ...ʣ • NotificationCenter • URLSession •
KVOʢKey-value observingʣ • Callback࣮ʢDelegate, Closureʣ 3
ඇಉظॲཧʹ͓͚Δ՝ • ωετͨ͠Closure Callbackࠈ • Delegateॻ͘ͷಡΉͷΊΜͲ͍͘͞ࠈ • ඇಉظΠϕϯτͷछྨ࣮͍Ζ͍ΖɺྲྀΕ͕Θ͔Βͳ͘ͳ Δ 4
Combine͜ΕΒͷඇಉظॲཧΛ Ұݩతɺએݴతʹѻ͏ͨΊͷAPI 5
ओͳAPI • Publisher • Subscriber • Operator 6
Publisher • Τϥʔ͕ͲͷΑ͏ʹൃੜ͢Δ͔Λఆٛ • SubscriberͷొΛՄೳʹ͢Δʢߪಡʣ • ࣮ܕʢstructʣ 7
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
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
ฦ͞ͳ͍ͷͬͯVoid͡Όͳ͍ͷʁ 10
Neverܕ public enum Never {} • ࣮caseͳ͠enum • ͭ·ΓΛͭ͘Εͳ͍͜ͱΛදݱ 11
Voidܕ public typealias Void = () • ࣮ۭͷλϓϧͷΤΠϦΞε • ͭ·ΓۭͷλϓϧΛฦ͍ͯ͠Δ
12
fatalErrorͷΓNeverܕ class ViewController: UIViewController init() { ... } required init?(coder
aDecoder: NSCoder) { // NeverܕΛฦ͢͜ͱͰϓϩάϥϜऴྃ fatalError("init(coder:) has not been implemented") } func hoge() -> Int { // ΓͷܕݕࠪߦΘΕͳ͍ͷͰ // ͜ΕͰίϯύΠϧ͕௨Δ fatalError() } } 13
Subscriber • ͱྃΛड͚औΔ • ࢀরܕʢclassʣ 14
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
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
Operator • Publisherϓϩτίϧʹ४ڌ • ͕มԽ͢Δ;Δ·͍Λఆٛ • ܕʢstructʣ 17
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
OperatorͰͰ͖Δ͜ͱͷҰྫ • ؔతͳͷม • Ϧετૢ࡞ • ΤϥʔϋϯυϦϯά • εϨουɺΩϡʔΠϯάॲཧʢαϒεϨουॲཧʣ •
εέδϡʔϦϯάʢλΠϚʔॲཧʣ 19
Publisher, Subscriber, OperatorΛͬͯΈΔ ຐ๏ֶߍͱֶ class Wizard { var grade: Int
init(grade: Int) { self.grade = grade } } let merlin = Wizard(grade: 5) 20
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
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
ϝιουνΣΠϯͰΑΓએݴతʹ 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
ϝιουνΣΠϯͰΑΓએݴతʹ compactMapfilterɺprefixͳͲArrayͰݟ׳Εͨؔ let cancellable = NotificationCenter.default.publisher(for: .graduated, object: merlin) .compactMap
{ note in return note.userInfo?["NewGrade"] as? Int } .filter { $0 >= 5 } .prefix(3) .assign(to: \.grade, on: merlin) 24
௨৴ॲཧʹ͑ͦ͏ͳͷଟ͍ https://developer.apple.com/documentation/combine/publishers • Zip, Zip3, Zip4, CombineLatest: ͪ߹Θͤ • Decode:
σίʔυॲཧ • Retry: ϦτϥΠ • Throttle, Debounce: ࿈ଓ͢ΔΠϕϯτΛݮΒ͢ʢ࿈ଧɺΠϯΫϦϝϯλϧαʔ νʣ • Timeout: λΠϜΞτ 25
௨৴ॲཧͷ࣮ྫ 26
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
Viewͱͷ࿈ܞ • SwiftUI • ObservableObject/Published • UIKit • UICollectionViewDiffableDataSource •
UITableViewDiffableDataSource 28
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
͓ΘΓ 30