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
健康的なMVVM 書いてますか? ~MVVMアンチパターン集~
Search
takasek
April 27, 2016
Programming
21k
26
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
健康的なMVVM 書いてますか? ~MVVMアンチパターン集~
Health Swift Meetup (
http://finc-swift.connpass.com/event/29901/
) の発表資料です。
takasek
April 27, 2016
More Decks by takasek
See All by takasek
影響スケッチでFatViewControllerを可視化してみよう' / 20200530 effect sketch #swiftzoomin
takasek
1
1.8k
Clean Architecture: クライアントアプリの「中心」とは何か / 20200121 the center of the client #ios_ca
takasek
10
3.9k
SOLID原則を生活に適用する / 20190906 iOSDC
takasek
4
13k
APIレスポンスにおける直和型の表現を考える / 20190730 sekkeikaigi
takasek
4
1.7k
Dark Mode / 20190617 #wwdc_rusuban
takasek
11
1.6k
継続渡しと契約による設計 / 20190319 #tryswift_pre
takasek
8
2.2k
Continuation-Passing Style and Design By Contract(English ver.) / 20190319(E) #tryswift_pre
takasek
1
380
FiNCのクライアントアーキテクチャを揃える試み / 20190110 #app_mp
takasek
1
7.4k
SOLID原則のSとDとテストの話 - 「Swiftらしく設計する」Another / 20181221 #roppongiswift
takasek
1
1.4k
Other Decks in Programming
See All in Programming
LoopHub - ローカルで動く GitHub で、AI と共同開発
jugyo
1
560
世界の中心で、AI(App Intents)をさけぶ ー App Intents中心設計の実践ガイド
touyou
0
600
一人だけ、Kiroが静止する日
hideg
0
110
モジュールの視点からSwiftを読み解く #iosdc
s_shimotori
0
180
海上で動くGoサーバー: goroutineとchannelでさばく航行データストリーム
atsuki_seo
0
720
thread_parallel_with_free-threaded_Python_and_NumPy.pdf
riku_sakamoto
0
340
LL言語やWebフレームワークのPostgreSQL対応 〜DBの機能がユーザーに届くまで〜
kentaroutakeda
1
150
AI に Inclusive UI を書かせよう — Design Rules Skill で Compose UI を作り直す
theoriatec2024
1
490
C#の現在地 進化の歴史と、AI時代の.NET Everywhere
neuecc
4
2.3k
Vue Fes Japan 2026 タイムテーブル徹底解説
448jp
1
250
WebMCP Challenge に星空観察アプリで参加した話
okajun35
0
180
手動確認はもう限界 〜XCUITestでCustom URL Schemeの遷移を起動種別ごとに自動テストする〜 / Testing Custom URL Schemes with XCUITest
otouto
0
300
Featured
See All Featured
It's Worth the Effort
3n
188
29k
Producing Creativity
orderedlist
PRO
348
41k
Efficient Content Optimization with Google Search Console & Apps Script
katarinadahlin
PRO
1
850
Gemini Prompt Engineering: Practical Techniques for Tangible AI Outcomes
mfonobong
2
530
Build your cross-platform service in a week with App Engine
jlugia
234
19k
Abbi's Birthday
coloredviolet
4
10k
The untapped power of vector embeddings
frankvandijk
2
1.9k
SEO for Brand Visibility & Recognition
aleyda
0
4.7k
The SEO identity crisis: Don't let AI make you average
varn
0
560
Being A Developer After 40
akosma
91
590k
The SEO Collaboration Effect
kristinabergwall1
1
570
WCS-LA-2024
lcolladotor
0
830
Transcript
݈߁తͳ.77. ॻ͍ͯ·͔͢ʁ d.77.Ξϯνύλʔϯूd )FBMUI4XJGU.FFUVQ CZ XJUI'J/$
!UBLBTFL w GSFFMBODFJ04&OHJOFFS w 'J/$͞ΜͰ͓ࣄ͍͍ͤͯͨͩͯ͞·͢ w ɹ!UBLBTFL w ɹUBLBTFL w
ɹUBLBTFL
!UBLBTFL w /PUJGXJGU IUUQTHJUIVCDPNUBLBTFL/PUJGXJGU /4/PUJpDBUJPOͷVTFS*OGPΛ 4XJGUZʹѻ͏ϚΠΫϩϥΠϒϥϦ w "DUJPO$MPTVSBCMF IUUQTHJUIVCDPNUBLBTFL"DUJPO$MPTVSBCMF UBSHFUBDUJPOΛ͢ॲཧΛ
4XJGUZͳΫϩʔδϟͰॻ͚Δ ϚΠΫϩϥΠϒϥϦ (JU)VCͰ 044ϥΠϒϥϦ࡞ͬͯ·͢
͓͞Β͍ .77.ͱ
.PEFM 7JFX.PEFM 7JFX %BUB #JOEJOH $PNNBOET ɹ%BUB#JOEJOHͷ࣮ݱͷͨΊʹɺJ04ͷ߹ ɹɹ'31ϥΠϒϥϦ 3Y4XJGU 3FBDUJWF$PDPB
ɹɹσʔλόΠϯσΟϯάϥΠϒϥϦ 4XJGU#POE ͷ ɹɹαϙʔτ͕ඞཁ ɹ ˞'J/$Ͱݱࡏ4XJGU#POEΛར༻
ຊ
͜Ε͔Β ෆ݈߁ͳ7JFX.PEFMΛ ͠·͢
Ͱ͠ΌΓ7JFX.PEFM Χϧςᶃ
class MyViewModel { weak var view: MyView? func doSomething(fuga: Fuga)
{ guard let view = view else { return } if view.isHoge { view.doSomething(fuga) } } } class MyView { func awakeFromNib() { viewModel.view = self } } Ͱ͠ΌΓ7JFX.PEFM ঢ় 7JFX.PEFM͕7JFXͷࢀরΛ࣋ͬͯɺૢ࡞͢Δ
Ͱ͠ΌΓ7JFX.PEFM පࠜ ࠜຊతʹઃܭ͕͓͔͍͠ w 7JFXʹमਖ਼͕ೖͬͨΒ7JFX.PEFMमਖ਼͠ͳ͖Όʜ w ͔ͤͬ͘ͷ.77.ύλʔϯ͕ແͩ͠ʂ w ʜͱ͍͏͔ɺ͜Ε.77.ʹͳͬͯͳ͍
ґଘͷํ 7JFXɹɹ7JFX.PEFM 7JFX.PEFMɹɹ.PEFM Ҿ༻"SDIJUFDUJOH"OESPJEʜ5IFDMFBOXBZ IUUQGFSOBOEPDFKBTDPNBSDIJUFDUJOHBOESPJEUIFDMFBOXBZ 7JFX.PEFM 7JFX σʔλόΠϯσΟϯά
Ͱ͠ΌΓ7JFX.PEFM ॲํᝦ w 7JFX.PEFMࣗࣗͷঢ়ଶΛมߋ͢Δ͚ͩ w Ͳ͏ΘΕΔ͔Ұؔ͠ͳ͍͠ɺ ୭ 7JFX ʹόΠϯυ͞Ε͍ͯΔ͔Βͳ͍ ʹ7JFXʹґଘ͠ͳ͍
ʹมߋʹڧ͍ 7JFX.PEFMˠ7JFX ඞͣόΠϯσΟϯάͰܨ͙
class MyViewModel { let fuga = Observable<Fuga?>(nil) func didReceiveFuga(fuga: Fuga)
{ self.fuga.value = fuga } } class MyView { func awakeFromNib() { viewModel.fuga.ignoreNil().observe { [weak self] in self?.doSomething($0) } } } Ͱ͠ΌΓ7JFX.PEFM վળྫ
ࠞઢ͍ͯ͠Δ 7JFX.PEFM Χϧςᶄ
ࠞઢ͍ͯ͠Δ7JFX.PEFM ঢ় 7JFX.PEFMͷίϚϯυ͕ ɹॲཧͷྃ࣌ʹ࣮ߦ͢ΔΫϩʔδϟΛड͚ͨΓ class MyView { func awakeFromNib() {
viewModel.alertMessage.observe { [weak self] in self?.showAlert($0) // ↓Ͳ͕ͬͪຊے!? } } func didTapButton() { viewModel.doSomething(completion: { [weak self] alertMessage in self?.showAlert(alertMessage) // ↑Ͳ͕ͬͪຊے!? }) } } ˠॲཧͷྲྀΕ͕ΧΦεʹʂ BMFSU.FTTBHF 0CTFSWBCMF4USJOH͕ มߋ͞ΕͨΒൃಈ ͳΜ͔ͬͨ݁Ռ BMFSU.FTTBHFΛ ड͚औΔ
ࠞઢ͍ͯ͠Δ7JFX.PEFM පࠜ ॲཧͷྲྀΕ͕ ཧͰ͖͍ͯͳ͍
ࠞઢ͍ͯ͠Δ7JFX.PEFM ॲํᝦ جຊɺ 7JFXˠ7JFX.PEFMίϚϯυΛୟ͚ͩ͘ 7JFX.PEFMˠ7JFXόΠϯυ͢Δ͚ͩ 7JFX.PEFM 7JFX %BUB #JOEJOH $PNNBOET
ᶃίϚϯυ ᶄঢ়ଶมߋ ᶅঢ়ଶө †એݴతʹهड़
Ψϥεͷ7JFX.PEFM Χϧςᶅ
class MyViewModel { let text = Observable<String>("") let textLength =
Observable<Int>(0) } vm.text.value = "ͳΜ͔͍ςΩετ" vm.text // "ͳΜ͔͍ςΩετ" vm.textLength // 0 ←!!?!!? Ψϥεͷ7JFX.PEFM ঢ় յΕͦ͏ͳ0CTFSWBCMF͔ΓूΊͯ͠·͏
Ψϥεͷ7JFX.PEFM පࠜ ঢ়ଶͷओैؔΛ એݴతʹදݱͰ͖͍ͯͳ͍ w UFYUΛมߋͨ͠Βɺ ͦͷϝιουͰUFYU-FOHUI มߋ͢ΔΑ͏ʹؾΛ͚ͭΔʁ ͍͍ɺͦΜͳͷਓ͕ؒ έΞ͖͢͜ͱ͡Όͳ͍͔Βʂ
ຖճҪށ͔Β ਫΛ·͞ΕͯΔΑ͏ͳ ॏ࿑ಇײ
Ψϥεͷ7JFX.PEFM ॲํᝦ $PMEͳ0CTFSWBCMFΛ͏ )PU 0CTFSWBCMF $PME &WFOU1SPEVDFS
class MyViewModel { let text = Observable<String>("") let textLength: EventProducer<Int>
init() { textLength = text.map { $0.characters.count } } } vm.text // "ͳΜ͔͍ςΩετ" vm.textLength // 9 Ψϥεͷ7JFX.PEFM վળྫ ɹUFYU-FOHUINBQ USBOTGPSNJOHPQFSBUPS Λ௨͚ͩ͢ͷ ɹ$PMEͳଘࡏʹ͠ɺ߹ੑΛอূ એݴతʹهड़Ͱ͖ͨʂ
ઉΒͣͳ 7JFX.PEFM Χϧςᶆ
class MyViewModel { let name = Observable<String>("") let address =
Observable<String>("") } let vm = MyViewModel() vm.name.observe { func setUserData() } vm.address.observe { func setUserData() } func setUserData(userId: Int) { userNameLabel.text = vm.name userAddressLabel.text = vm.address } ઉΒͣͳ7JFX.PEFM ঢ় ɹ7JFX.PEFMͷมԽΛड͚औͬͨ7JFX͕ɺ ɹվΊͯ7JFX.PEFMͷϓϩύςΟΛࢀর͍ͯ͠Δ OBNFͱBEESFTT ͲͪΒ͕มߋ͞Εͯ ྆ํΛͬͯߋ৽ॲཧΛ ߦ͍͍ͨʂ
ઉΒͣͳ7JFX.PEFM පࠜ σʔλΛదͳཻɾͰ ͍ͯ͠ͳ͍
ઉΒͣͳ7JFX.PEFM ॲํᝦ ֤छΦϖϨʔλΛ͍͜ͳ͢ class MyViewModel { let name = Observable<String>("")
let address = Observable<String>("") lazy var nameAndAddress: EventProducer<(String, String)> = { return combineLatest(self.name, self.address) }() } let vm = MyViewModel() vm.nameAndAddress.observe { name, address in userNameLabel.text = name userAddressLabel.text = address } IUUQSYNBSCMFTDPNͱ͔ࢀߟʹͳΔΑ OBNFͱBEESFTT͕ λϓϧͰͬͯ͘Δ
ಜෆߦಧͳ 7JFX.PEFM Χϧςᶇ
class MyView { var viewType: ViewType func setup(viewType: ViewType) {
self.viewType = viewType switch viewType { case .Title: viewModel.title.observe { ... } case .Image: viewModel.image.observe { ... } case .Detail: viewModel.detail.observe { ... } } } } ಜෆߦಧͳ7JFX.PEFM ঢ় 7JFXଆʹঢ়ଶ݅ذ͕͋Δ
ಜෆߦಧͳ7JFX.PEFM පࠜ ঢ়ଶ݅அͷίʔυΛ 7JFX.PEFMʹҠ͍ͯ͠ͳ͍
ͦͦ7JFX.PEFM.PEFMͷӨͳͷͰ͢ɻ ͦͯ͠·ͨ7JFX7JFX.PEFMͷӨͰ͋Γ·͢ɻ Ҿ༻.77.ͷ.PEFMʹ·ͭΘΔޡղUIFTFBPGGFSUJMJUZ IUUQVHBZBIBUFCMPKQFOUSZNPEFMNJTUBLF
ಜෆߦಧͳ7JFX.PEFM ॲํᝦ ʮ7JFX7JFX.PEFMͷӨʯΛ పఈͤ͞Δ class MyView { func awakeFromNib() {
viewModel.title.observe { ... } viewModel.image.observe { ... } viewModel.detail.observe { ... } } } 7JFXԿஅΛߦΘͣɺ 7JFX.PEFMͷঢ়ଶΛ ʑͱ6*ʹөͤ͞Δ 7JFX.PEFMɺ 7JFXΛ࠶ߏͰ͖Δ͚ͩͷ ঢ়ଶใΛอ࣋͢Δ
ਆܦ࣭ͳ 7JFX.PEFM Χϧςᶈ
ਆܦ࣭ͳ7JFX.PEFM ঢ় 7JFX.PEFM͕ঢ়ଶΛࡉ͔࣋ͪ͗ͯ͘͢ΧΦε ɾμΠΞϩάͷදࣔඇදࣔঢ়ଶͱ͔ ɾը໘ભҠͷঢ়ଶͱ͔
ਆܦ࣭ͳ7JFX.PEFM පࠜ ʮঢ়ଶʯͱʮشൃੑͷݱʯΛ ۠ผͰ͖͍ͯͳ͍ ˞شൃੑͷݱඞͣফ͑Ώ͘ͷɻ
ਆܦ࣭ͳ7JFX.PEFM ॲํᝦ 0CTFSWBCMF7PJE class MyViewModel { let isUpdated = Observable<Void>()
private func didSomething() { isUpdated.next() } } 81' 8JOEPXT1SFTFOUBUJPO'PVOEBUJPO ʹ .FTTFOHFSͱ͍͏֓೦͕͋Δ 7JFX.PEFM͕Πϕϯτͷൃߦͱ͍͏ܗͰ7JFXʹ௨͢ΔΈ ղܾ͍ͨ͠ಉ͡ʜ ͩͱࢥ͏Μ͚ͩͲɺ 81'ͷݟ͕ͳ͍ͷͰ ؒҧͬͯͨΒ͢Έ·ͤΜʜ ͱΓ͋͑ͣ 0CTFSWBCMF7PJEศརͰ͢
ϝλϘϦοΫγϯυϩʔϜ 7JFX.PEFM Χϧςᶉ
ϝλϘͳ7JFX.PEFM ঢ় 7JFX.PEFM͕ ɹ ɹ௨৴ॲཧ ɹσʔλΩϟογϡ ɹ͞·͟·ͳۀͷϋϯυϦϯά ɹʜΛߦ͍ͬͯΔ
ϝλϘͳ7JFX.PEFM පࠜ .PEFMʹ͍ͭͯ ޡղͯ͠·ͤΜ͔
ϝλϘͳ7JFX.PEFM ॲํᝦ .PEFMΛ͔ͬ͠Γ࡞Ζ͏ .PEFM%"0 %BUB"DDFTT0CKFDU Ͱͳ͍ .PEFMۀϩδοΫ ඇ6*,JUͷผϓϥοτϑΥʔϜʹҠ২ͯ͠มΘΒͳ͍෦ Α͘7JFX$POUSPMMFSʹߦ͘Β͍ॻ͔ΕͯΔͭ ͋Ε΄ͱΜͲ.PEFMʹॻ͖͘ͷ
;ͨͨͼҾ༻"SDIJUFDUJOH"OESPJEʜ5IFDMFBOXBZ IUUQGFSOBOEPDFKBTDPNBSDIJUFDUJOHBOESPJEUIFDMFBOXBZ .77. ΞʔΩςΫνϟશମΛΧόʔͰ͖Δ֓೦Ͱͳ͘ ද෦ͷ࣮ʹա͗ͳ͍
.PEFM 7JFX.PEFM 7JFX %BUB #JOEJOH $PNNBOET ͜ͷ࿈ܞʹ͍ͭͯ.77.Կنఆͯ͠ͳ͍ ʢ.7˓શ෦ͦ͏͚ͩͲʣ
ͦ͏͍͏ͱ͜Λҙࣝͭͭ͠ɺ ΞϓϦશମʹΛͬͯ ݈߁తͳઃܭΛ͠ɺ ݈߁తͳίʔυΛॻ͖ɺ ݈߁తͳΤϯδχΞϥΠϑΛૹΓ·͠ΐ͏ʂ
'J/$Ͱ ݈߁తͳΤϯδχΞؒΛืू͍ͯ͠·͢