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
Transcript
43 slides
݈߁తͳ.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/$Ͱ ݈߁తͳΤϯδχΞؒΛืू͍ͯ͠·͢
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
390
FiNCのクライアントアーキテクチャを揃える試み / 20190110 #app_mp
takasek
1
7.5k
SOLID原則のSとDとテストの話 - 「Swiftらしく設計する」Another / 20181221 #roppongiswift
takasek
1
1.4k
Other Decks in Programming
See All in Programming
どうしても Eloquent でリポジトリパターンをやりたいんだ #phpcon_niigata / phpcon-niigata-2026
shogogg
0
310
ビジネスロジックを堅牢に~Scala 3のドメインプリミティブ~
j5ik2o
0
180
Scalaの型でマルチテナントの認可を守る
nextbeatdev
0
130
なぜ私たちは「現時点では」KMPの導入を見送ったのか
chigichan24
0
230
複数ドメインを一つのアプリに統合するFlutterの設計と運用_FlutterKaigi2026登壇資料(須永高弘)
takahirosunaga
0
190
AIが生成したコードは読むべきか?抽象化設計とコードの品質保証 / abstraction-design-and-quality
minodriven
16
9.2k
React Native経験者が Flutterを30⽇間触って驚いたこと
3saito
0
190
オーケストレーション記述言語 Katari
yukikurage
0
260
地方こそサーバーレス — 10年続けた、顔が見えるチームで確かな基盤を / Serverless Matters Most in Regional Areas — 10 Years of Building Reliable Foundations with Close-Knit Teams
seike460
PRO
1
460
AI時代のシニアエンジニアとは
yosuke_furukawa
PRO
15
12k
あなたの await、OS まで届いてる? strace で覗く JavaScript の非同期
hasutosasaki
1
2.4k
[DroidKnights 2026] Workflow AX: From Auto-Documented Policies to E2E Testing
raeminkang
0
570
Featured
See All Featured
JavaScript: Past, Present, and Future - NDC Porto 2020
reverentgeek
52
6.2k
Cheating the UX When There Is Nothing More to Optimize - PixelPioneers
stephaniewalter
287
14k
The Illustrated Guide to Node.js - THAT Conference 2024
reverentgeek
1
610
Embracing the Ebb and Flow
colly
88
5.2k
Raft: Consensus for Rubyists
vanstee
143
7.9k
Gemini Prompt Engineering: Practical Techniques for Tangible AI Outcomes
mfonobong
2
640
The Curse of the Amulet
leimatthew05
4
17k
The Invisible Side of Design
smashingmag
301
52k
10 Git Anti Patterns You Should be Aware of
lemiorhan
PRO
659
62k
Reality Check: Gamification 10 Years Later
codingconduct
0
2.4k
Introduction to Domain-Driven Design and Collaborative software design
baasie
1
1.1k
Color Theory Basics | Prateek | Gurzu
gurzu
1
520