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
@cosmeアプリでのRx活用
Search
Sponsored
·
Your Podcast. Everywhere. Effortlessly.
Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
→
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
1k
みんなでエラー監視するSRE夕会の効果_ゆるSRE勉強会1
yuyaabo
1
730
Go 1.19.1 security fix net/url JoinPath
yuyaabo
1
560
HTTPステータスコードが意図した値にならないとき Let's Go Talk #2
yuyaabo
1
560
OSS貢献を気軽にしたい Let's Go Talk #1
yuyaabo
2
660
困ったときが学びどき.pdf
yuyaabo
0
650
Build dynamic iOS apps with the Create ML framework の要約
yuyaabo
0
1.3k
fastlaneベースでTravis CIからBitriseに移行しました
yuyaabo
0
1.9k
Mixpanelのすゝめ
yuyaabo
0
3k
Other Decks in Programming
See All in Programming
ふつうのFeature Flag実践入門
irof
7
3.6k
タクシーアプリ『GO』の バックエンド開発のおける AI利活用と若者のすべて
pyama86
3
1.9k
Observability in Practice:Grafana 與 Edge Device SRE 的那些事
blueswen
0
150
Language Server 使ってる? 〜VSCode と Zed の場合〜 / Are you using a Language Server? ~For VS Code and Zed~
handlename
0
770
3Dシーンの圧縮
fadis
1
680
プロパティの順序で型推論が壊れる!? TypeScript6.0の修正からContext-Sensitivityの仕組みを追う
bicstone
2
1.3k
IBM Bobを活用したレガシーアプリの最新化
oniak3ibm
PRO
1
180
脅威をエンジニアリングの糧にして――現場編 / Turning Threats into Engineering Fuel — Field Edition
nrslib
0
260
メソッドのジェネリクスでGoの夢は広がるか? / Kyoto.go #65
utgwkk
3
640
並列実装の現場、2ヶ月間実務でAIを使い倒したAIもPCも私も限界が近い
ming_ayami
0
110
TAKTでAI駆動開発の品質を設計する
j5ik2o
6
1.1k
生成AI時代にこそ効くGo | Why Go Works in the Age of Generative AI
mom0tomo
8
3.2k
Featured
See All Featured
Learning to Love Humans: Emotional Interface Design
aarron
275
41k
Effective software design: The role of men in debugging patriarchy in IT @ Voxxed Days AMS
baasie
0
400
Optimizing for Happiness
mojombo
378
71k
The Cost Of JavaScript in 2023
addyosmani
55
10k
The Cult of Friendly URLs
andyhume
79
6.9k
Money Talks: Using Revenue to Get Sh*t Done
nikkihalliwell
0
250
We Are The Robots
honzajavorek
0
240
How to Ace a Technical Interview
jacobian
281
24k
Redefining SEO in the New Era of Traffic Generation
szymonslowik
1
330
sira's awesome portfolio website redesign presentation
elsirapls
0
270
Why Your Marketing Sucks and What You Can Do About It - Sophie Logan
marketingsoph
0
160
Evolving SEO for Evolving Search Engines
ryanjones
0
210
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/ ͓ΘΓʹ