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
260
Combine入門
AppleのCombineフレームワークの基本的な内容について
shtnkgm
June 11, 2020
Tweet
Share
More Decks by shtnkgm
See All by shtnkgm
Property Wrappers
shtnkgm
0
300
Saliency Detection
shtnkgm
0
25
パフォーマンス改善とユニットテスト
shtnkgm
4
1.6k
iOSのコードベースレイアウト
shtnkgm
2
730
20190117_iOSLT_CBLinSwift.pdf
shtnkgm
0
68
SwiftとFunctional Reactive Programming
shtnkgm
0
150
20180710_iOSLT_iOSでDarkModeを実装する
shtnkgm
0
71
20180410_iOSLT_SwiftとProtocol-OrientedProgramming
shtnkgm
0
88
20180220_iOSLT_Swiftとオブジェクト間の通知のパターン
shtnkgm
0
100
Other Decks in Programming
See All in Programming
CI改善もDatadogとともに
taumu
0
120
GAEログのコスト削減
mot_techtalk
0
120
Amazon Bedrock Multi Agentsを試してきた
tm2
1
290
Pulsar2 を雰囲気で使ってみよう
anoken
0
240
苦しいTiDBへの移行を乗り越えて快適な運用を目指す
leveragestech
0
580
2024年のWebフロントエンドのふりかえりと2025年
sakito
2
250
Formの複雑さに立ち向かう
bmthd
1
850
PHPのバージョンアップ時にも役立ったAST
matsuo_atsushi
0
110
Honoとフロントエンドの 型安全性について
yodaka
7
1.2k
AWS Organizations で実現する、 マルチ AWS アカウントのルートユーザー管理からの脱却
atpons
0
150
パスキーのすべて ── 導入・UX設計・実装の紹介 / 20250213 パスキー開発者の集い
kuralab
3
780
データベースのオペレーターであるCloudNativePGがStatefulSetを使わない理由に迫る
nnaka2992
0
150
Featured
See All Featured
Fantastic passwords and where to find them - at NoRuKo
philnash
51
3k
How to Ace a Technical Interview
jacobian
276
23k
Building a Scalable Design System with Sketch
lauravandoore
461
33k
The Language of Interfaces
destraynor
156
24k
Stop Working from a Prison Cell
hatefulcrawdad
267
20k
Code Review Best Practice
trishagee
67
18k
Visualization
eitanlees
146
15k
Practical Tips for Bootstrapping Information Extraction Pipelines
honnibal
PRO
12
960
Rails Girls Zürich Keynote
gr2m
94
13k
Making Projects Easy
brettharned
116
6k
Thoughts on Productivity
jonyablonski
69
4.5k
Distributed Sagas: A Protocol for Coordinating Microservices
caitiem20
330
21k
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