Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
Combine入門
Search
shtnkgm
June 11, 2020
Programming
330
2
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Combine入門
AppleのCombineフレームワークの基本的な内容について
shtnkgm
June 11, 2020
More Decks by shtnkgm
See All by shtnkgm
Property Wrappers
shtnkgm
0
380
Saliency Detection
shtnkgm
0
90
パフォーマンス改善とユニットテスト
shtnkgm
4
1.8k
iOSのコードベースレイアウト
shtnkgm
2
840
20190117_iOSLT_CBLinSwift.pdf
shtnkgm
0
130
SwiftとFunctional Reactive Programming
shtnkgm
0
210
20180710_iOSLT_iOSでDarkModeを実装する
shtnkgm
0
130
20180410_iOSLT_SwiftとProtocol-OrientedProgramming
shtnkgm
0
140
20180220_iOSLT_Swiftとオブジェクト間の通知のパターン
shtnkgm
0
170
Other Decks in Programming
See All in Programming
C#の現在地 進化の歴史と、AI時代の.NET Everywhere
neuecc
5
5.1k
自サークルのIdPからログアウトできるようになるまで
taiseiue
1
140
現場と育てるRailsモデリング 〜Spreadsheetから始めたモデル設計〜
siroemk
2
420
APNsからLive Activityを開始する話
yumnumm
0
170
SREの越境 / SRE Collaboration
y0hgi
2
310
外から家のPCの電源入れたい!をPHPで解決する
kawashimo0
1
130
Verilogで学ぶCPU自作入門
uyuki234
8
4.1k
Findy - エンジニア向け会社紹介/Findy Company Deck
findyinc
6
400k
Augmenting AI with the Power of Jakarta EE
ivargrimstad
0
120
UPDATE をやめる — EF Core でマスタをバージョン管理する
panda728
PRO
0
1.2k
プロダクトコードからライブラリの境界を見つける
elmetal
PRO
0
120
作れる、でも消せるか?──安全に「枯らして消す」機能削除術 / Drain, Then Delete
chobishiba
1
190
Featured
See All Featured
Groundhog Day: Seeking Process in Gaming for Health
codingconduct
0
410
Scaling GitHub
holman
464
140k
Done Done
chrislema
187
17k
Why Your Marketing Sucks and What You Can Do About It - Sophie Logan
marketingsoph
0
430
Creating an realtime collaboration tool: Agile Flush - .NET Oxford
marcduiker
35
2.6k
Lessons Learnt from Crawling 1000+ Websites
charlesmeaden
PRO
1
1.6k
How to Get Subject Matter Experts Bought In and Actively Contributing to SEO & PR Initiatives.
livdayseo
0
220
Easily Structure & Communicate Ideas using Wireframe
afnizarnur
194
17k
Organizational Design Perspectives: An Ontology of Organizational Design Elements
kimpetersen
PRO
1
850
Jamie Indigo - Trashchat’s Guide to Black Boxes: Technical SEO Tactics for LLMs
techseoconnect
PRO
0
700
jQuery: Nuts, Bolts and Bling
dougneiner
66
8.6k
Git: the NoSQL Database
bkeepers
PRO
433
67k
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