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
@cosmeアプリでのRx活用
Search
aboy
November 26, 2018
Programming
1.6k
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
@cosmeアプリでのRx活用
15分ver
aboy
November 26, 2018
More Decks by aboy
See All by aboy
生成AIで日々のエラー調査を進めたい
yuyaabo
0
1.1k
みんなでエラー監視するSRE夕会の効果_ゆるSRE勉強会1
yuyaabo
1
740
Go 1.19.1 security fix net/url JoinPath
yuyaabo
1
580
HTTPステータスコードが意図した値にならないとき Let's Go Talk #2
yuyaabo
1
580
OSS貢献を気軽にしたい Let's Go Talk #1
yuyaabo
2
680
困ったときが学びどき.pdf
yuyaabo
0
660
Build dynamic iOS apps with the Create ML framework の要約
yuyaabo
0
1.3k
fastlaneベースでTravis CIからBitriseに移行しました
yuyaabo
0
1.9k
Mixpanelのすゝめ
yuyaabo
0
3.1k
Other Decks in Programming
See All in Programming
phperだってパンチカードでコーディングしたい
o0h
PRO
0
270
Verilogで学ぶCPU自作入門
uyuki234
8
4.1k
UPDATE をやめる — EF Core でマスタをバージョン管理する
panda728
PRO
0
1.2k
最近”作らせてる” ローカルAIアプリの話
akit37
0
440
Atomic Design, Enforced: Scaling Mobile Design Systems (next.app devCon / droidCon Berlin 2026)
steliosf
PRO
0
160
APNsからLive Activityを開始する話
yumnumm
0
160
ソニーのクラウド共通基盤の変遷とAI時代の開発スタイルに合わせた進化 / The Journey of Sony’s Common Cloud Platform and Its Evolution for AI-Native Development
kenjiyoneyama
0
250
AI主導のプログラミング学習アプリを作ってみた
econanringo
0
150
Everything will be SERVERLESS — 信じて運用した10年の経験値 / Everything Will be Serverless — Lessons Learned from 10 Years of Operational Experience
seike460
PRO
1
970
設計次第でAIコードの読む量は減らせる / designing-for-code-reading
minodriven
34
16k
Agentic Software Factoryに、すごく賢いIF文を。 / super smart IF statement into the Agentic Software Factory.
rkaga
8
2.1k
JAWS-UG 東京支部が始める、JAWS-UG支部コラボ / JAWS-UG lunchtime LT Collaboration
y0hgi
0
220
Featured
See All Featured
Music & Morning Musume
bryan
48
7.4k
Imperfection Machines: The Place of Print at Facebook
scottboms
270
14k
The Success of Rails: Ensuring Growth for the Next 100 Years
eileencodes
47
8.4k
Pawsitive SEO: Lessons from My Dog (and Many Mistakes) on Thriving as a Consultant in the Age of AI
davidcarrasco
0
260
Heart Work Chapter 1 - Part 1
lfama
PRO
10
37k
Embracing the Ebb and Flow
colly
88
5.2k
WENDY [Excerpt]
tessaabrams
14
40k
Intergalactic Javascript Robots from Outer Space
tanoku
273
27k
Save Time (by Creating Custom Rails Generators)
garrettdimon
PRO
33
5.2k
Facilitating Awesome Meetings
lara
57
7.2k
Leveraging LLMs for student feedback in introductory data science courses - posit::conf(2025)
minecr
1
430
Exploring the Power of Turbo Streams & Action Cable | RailsConf2023
kevinliebholz
37
6.6k
Transcript
ˏcosmeΞϓϦͰͷRx׆༻ dip × istyle ߹ಉษڧձ#02 15
• Ѩอ༑ aboy • גࣜձࣾΞΠελΠϧͰɺˏcosmeΞϓϦˏcosmePROΞϓϦͷ։ൃΛ͍ͯ͠·͢ • iOSΞϓϦͱɺΞϓϦ༻APIήʔτΣΠΛ୲தͰ͢ • ೫ࡔ46͕͖ͳͷͰɺόΠτϧCMʹ͍ͭݩؾΛ͍͍͍ͨͩͯ·͢ɻdip͞ΜͱͯૉΒ͠ ͍ͱࢥ͍ͬͯ·͢ɻ͍ͭ͋Γ͕ͱ͏͍͟͝·͢ɻ
ࣗݾհ
ࠓ͢͜ͱ • ˏcosmeΞϓϦͰRxΛͬͯ։ൃ͍ͯ͠·͢ɻRxͷ׆༻ྫΛɺαϯϓϧίʔυΛަ͑ͯհ͠·͢ • εϥΠυͷαϯϓϧίʔυSwift(RxSwift/RxCocoa)Ͱ͢ɻઆ໌༻ͳͷͰɺʮ͋ΕΓͳ͍ Αʂʯͱ͍͏͕͍͔ͭͭ͋͘Γ·͢ɻΤϥʔϋϯυϦϯάͳ͍Ͱ͢ɻ ͞ͳ͍͜ͱ • ObservableͷHot/ColdError,CompletedͳͲɺRxͷৄ͍͠આ໌
Rxͱʁ
Rxͱʁ • Reactive Extensionsͷ͜ͱͰ͢ • Reactive ExtensionsͱɺϚΠΫϩιϑτ͔Β·ͬͨɺReactive ProgrammingΛ࣮ݱ͢Δ ͨΊͷσβΠϯɺͦͷ࣮ϥΠϒϥϦͷ͜ͱͰ͢ •
Reactive Programmingͱɺͬ͘͟Γݴ͏ͱprint(b)͕4Λग़ྗ͢ΔΑ͏ͳύϥμΠϜͰ͢ • ˏcosmeΞϓϦͰɺRxSwift(iOS)ɺRxJava(Android)Λ࣮ͬͯݱ͍ͯ͠·͢ a = 1 b = 2 * a a = 2 print(b)
Rxͱʁ • RxΦϒβʔόʔύλʔϯΛ༻͍࣮ͯ͞Ε͍ͯ·͢ • RxͰग़ͯ͘Δجຊతͳ֓೦Λ3ͭͬ͘͟Γઆ໌͠·͢ • ObservableͱɺߪಡՄೳͰ͋ΓɺΠϕϯτΛྲྀ͢ͷͰ͢ • OperatorsͱɺObservableΛมԽͤ͞ΔԋࢉࢠͷΑ͏ͳͷͰ͢ •
Subscribe(ߪಡ)ͱɺObservable͔ΒྲྀΕͯ͘ΔΠϕϯτΛࢹ͢Δ͜ͱͰ͢
Rxͱʁ let a = BehaviorSubject<Int>(value: 1) let b: Observable<Float> =
a .map { 2 * $0 } .map { Float($0) } b.subscribe(onNext: { (value: Float) in print(value) }) a.onNext(2) // 2.0 // 4.0 Observable Operators Subscribe ※1 ※1: BehaviorSubjectݫີʹObservableͰ͋ΓObserverͰ͢
ˏcosmeΞϓϦ × Rx • RxͷσʔλόΠϯσΟϯάػߏɺඇಉظॲཧͱͷ૬ੑͷྑ͞ΛϝϦοτʹײ͡ɺ1લͷˏcosme ΞϓϦϦχϡʔΞϧͷλΠϛϯάͰRxΛಋೖ͠·ͨ͠
ˏcosmeΞϓϦͰͷ׆༻ྫ
• ձһొը໘ͷσʔλόΠϯσΟϯά • ϝοηʔδεϨουϦετͷϙʔϦϯά • ඇಉظॲཧͷΈ߹Θͤ ׆༻ྫ
• ձһొը໘ͷσʔλόΠϯσΟϯά • ϝοηʔδεϨουϦετͷϙʔϦϯά • ඇಉظॲཧͷΈ߹Θͤ ׆༻ྫ
• ϝϧΞυͱύεϫʔυΛೖྗͯ͠ձһొ ͕Ͱ͖Δ • ϝϧΞυͱύεϫʔυʹͦΕͧΕόϦσʔ γϣϯ͕͋Δ • ྆ํOKͩͬͨΒձһొϘλϯ͕༗ޮԽ • όϦσʔγϣϯ݁ՌʹԠͯ͡ΤϥʔςΩε
τΛදࣔ ׆༻ྫɿձһొը໘ͷσʔλόΠϯσΟϯά
class SignUpViewModel { let password = Variable<String>("") } class SignUpViewController:
UITableViewController { @IBOutlet weak var passwordTextField: UITextField! private var viewModel: SignUpViewModel! override func viewDidLoad() { super.viewDidLoad() viewModel.password.asObservable() .bind(to: passwordTextField.rx.text) passwordTextField.rx.text.orEmpty .bind(to: viewModel.password) } } UI -> ViewModelͷόΠϯσΟϯά ViewModel -> UIͷόΠϯσΟϯά Input/Output݉ͷObservable ձһొը໘ɿجຊతͳσʔλόΠϯσΟϯά ※1 ※1: VariableRxSwiftಠࣗͷͷͰɺBehaviorSubjectͷϥούʔͰ͢ɻݱࡏdeplicatedͰ͢ɻ
class SignUpViewModel { private var isEmailValid: Observable<Bool> private var isPasswordLengthValid:
Observable<Bool> private var isPasswordCharacterValid: Observable<Bool> private var isPasswordValid: Observable<Bool> let canSignUp: Observable<Bool> init() { isEmailValid = email.asObservable() .map { (str: String) -> Bool in ϝϧΞυόϦσʔγϣϯ(str) } isPasswordCharacterValid = password.asObservable() .map { ύεϫʔυόϦσʔγϣϯ($0) } isPasswordLengthValid = password.asObservable() .map { 4 <= $0.count && $0.count <= 12 } isPasswordValid = Observable .combineLatest( isPasswordLengthValid, isPasswordCharacterValid ) { $0 && $1 } canSignUp = Observable .combineLatest(isEmailValid, isPasswordValid) { $0 && $1 } } } combineLatestෳͷΞΠςϜͷ࠷৽ͷ݁ՌΛ݁߹͠ɺ ධՁؔʹج͍ͮͯมͯ͠ฦ͢ΦϖϨʔλʔ mapΞΠςϜΛม͢ΔΦϖϨʔλʔ Stringܕ -> Boolܕͷม (Bool, Bool)ܕ -> Boolܕͷม ձһొը໘ɿձһొϘλϯͷ༗ޮԽ
class SignUpViewController: UIViewController { @IBOutlet private weak var signUpButton: UIButton!
private let viewModel = SignUpViewModel() override func viewDidLoad() { super.viewDidLoad() viewModel.canSignUp .bind(to: signUpButton.rx.isEnabled) } } ViewModel->UIͷόΠϯσΟϯά ೖྗ͞Εͨσʔλʹج͍ͮͨ ొϘλϯͷ༗ޮ/ඇ༗ޮԽ͕࣮ݱͰ͖Δ ձһొը໘ɿձһొϘλϯͷ༗ޮԽ
class SignUpViewModel { private var isPasswordLengthValid: Observable<Bool> private var isPasswordCharacterValid:
Observable<Bool> let passwordInvalidText: Observable<String> init() { isPasswordCharacterValid = password.asObservable() .map { ύεϫʔυόϦσʔγϣϯ($0) } isPasswordLengthValid = password.asObservable() .map { 4 <= $0.count && $0.count <= 12 } passwordInvalidText = Observable .combineLatest(isPasswordCharacterValid, isPasswordLengthValid) .map({ (charValid: Bool, lenValid: Bool) -> String in if !charValid { return "ύεϫʔυʹ༻Ͱ͖ͳ͍จࣈؚ͕·Ε͍ͯ·͢ɻ" } else if !lenValid { return "ύεϫʔυ4จࣈҎ্ɺ12จࣈҎͰೖྗ͍ͯͩ͘͠͞ɻ" } return "" }) } } όϦσʔγϣϯ݁ՌʹԠͨ͡ςΩετΛฦ͢ ձһొը໘ɿόϦσʔγϣϯ݁ՌͷΤϥʔςΩετ
class SignUpViewController: UIViewController { @IBOutlet private weak var passwordInvalidLabel: UILabel!
private let viewModel = SignUpViewModel() override func viewDidLoad() { super.viewDidLoad() viewModel.isPasswordInvalidLabelHidden .bind(to: passwordInvalidLabel.rx.isHidden) viewModel.passwordInvalidText .bind(to: passwordInvalidLabel.rx.text) } } ձһొը໘ɿόϦσʔγϣϯ݁ՌͷΤϥʔςΩετ Model->UIͷόΠϯσΟϯά
• ձһొը໘ͷσʔλόΠϯσΟϯά • ϝοηʔδεϨουϦετͷϙʔϦϯά • ඇಉظॲཧͷΈ߹Θͤ ׆༻ྫ
• Ұఆ࣌ؒ͝ͱʹAPIܦ༝Ͱσʔλऔಘ • εϨουͷߋ৽͕͋ΕϦετ(UI)Λߋ৽ ׆༻ྫɿϝοηʔδεϨουϦετͷϙʔϦϯά
class ThreadsViewModel { private let timer: Observable<Int> let polling: Observable<Thread>
init(repo: ThreadRepositoryProtocol = ThreadRepository()) { timer = Observable<Int> .interval(10.0, scheduler: MainScheduler.instance) polling = timer .flatMapFirst({ (_) -> Observable<[Thread]> in return repo.fetchThreads() }) .filter { ߋ৽͕͋Δ͔($0) } } } ϝοηʔδεϨουϦετͷϙʔϦϯά intervalΦϖϨʔλʔ ҰఆִؒͰΠϕϯτΛൃߦ flatMapFirstΦϖϨʔλʔ ม & ॲཧதແࢹ filterΦϖϨʔλʔ trueͳΒΠϕϯτΛૹΔ
• ձһొը໘ͷσʔλόΠϯσΟϯά • ϝοηʔδεϨουϦετͷϙʔϦϯά • ඇಉظAPI௨৴ॲཧͷΈ߹Θͤ ׆༻ྫ
• ͻͱͭͷը໘ʹෳηΫγϣϯ(ෳछྨͷίϯςϯπ) Λදࣔ • ηΫγϣϯऔಘͰ͖ͨͷ͔Βදࣔ • ηΫγϣϯ1ɺෳͷAPI͔ΒෳͷσʔλΛऔಘͯ͠ දࣔɻAPIͷ݁ՌΛશͯͭ ׆༻ྫɿඇಉظAPI௨৴ॲཧͷΈ߹Θͤ ηΫγϣϯ1
ηΫγϣϯ2 ηΫγϣϯ3
class ViewModel { private let cosme1: Observable<Cosme> private let cosme2:
Observable<Cosme> private let cosme3: Observable<Cosme> let section1: Observable<Void> init() { section1 = Observable .zip(cosme1, cosme2, cosme3) .map { มॲཧ } } } ඇಉظAPI௨৴ॲཧͷΈ߹ΘͤɿηΫγϣϯ̍ͷ࣮ zipͰඞཁͳObservableΛ·ͱΊΔ Πϕϯτͪ߹ΘͤΔ
class ViewModel { private let cosme1: Observable<Cosme> private let cosme2:
Observable<Cosme> private let cosme3: Observable<Cosme> let section1: Observable<Section1> let sectionList: Observable<[Section]> init() { section1 = Observable .zip(cosme1, cosme2, cosme3) .map { มॲཧ } sectionList = Observable .merge(section1, section2, section3) .map { มॲཧ } } } ඇಉظAPI௨৴ॲཧͷΈ߹ΘͤɿऔಘͰ͖ͨηΫγϣϯ͔Βදࣔ mergeͰඞཁͳObservableΛ·ͱΊΔ Πϕϯτͪ߹Θͤ͠ͳ͍ zipͰඞཁͳObservableΛ·ͱΊΔ Πϕϯτͪ߹ΘͤΔ
class ViewController: UIViewController { @IBOutlet private weak var tableView: UITableView!
private let viewModel = ViewModel() override func viewDidLoad() { super.viewDidLoad() viewModel.sectionList.subscribe(onNext: { [weak self] (_) in self?.tableView.reloadData() }) } } ඇಉظAPI௨৴ॲཧͷΈ߹ΘͤɿऔಘͰ͖ͨηΫγϣϯ͔Βදࣔ ηΫγϣϯͷϦετ͕ߋ৽͞ΕΔͨͼʹUIΛߋ৽
• ˏcosmeΞϓϦͰͷRx׆༻ྫΛհ͠·ͨ͠ɻσʔλόΠϯσΟϯάػߏɺObservableΛΈ߹Θͤ ͯඇಉظॲཧΛॻ͚Δັྗతʹײ͍ͯ͡·͢ɻجຊతʹΞϓϦέʔγϣϯશମͰRx͕ΘΕ͍ͯ·͢ • RxݴޠʹΑΒͳ͍֓೦ͳͷͰɺ࣮ϥΠϒϥϦؒͷࠩҟΛআ͚ɺiOS/AndroidΤϯδχΞؒͰͷڞ ௨ݴޠͱͯ͠ػೳ͢ΔϝϦοτ͋Γ·͢ • σʔλͷ͍ʹ͘͞ՄಡੑɺֶशʹࢿͰ͖Δ͔ɺͳͲͷ؍ͰɺνʔϜ։ൃͰ࠾༻͢Δ͔Ͳ͏͔ͦ ͷ࣌ͦͷ࣌ʹΑͬͯݟۃΊΔඞཁ͕͋Δ͔ͱࢥ͍·͢ •
ωΠςΟϒΞϓϦք۾Ͱؔ৺ͷߴ͍ٕज़Ͱ͋Δͱࢥ͏ͷͰɺ͜Ε͔ΒΥον͍ͯ͘͠ͱ͍͍͔ ͱࢥ͍·͢ • ReactiveXͱ͍͏αΠτʹυΩϡϝϯτ֤ݴޠͷRxϥΠϒϥϦ͕·ͱ·͍ͬͯΔͷͰ͝ཡ͍ͩ͘͞ http://reactivex.io/ ͓ΘΓʹ