Upgrade to Pro — share decks privately, control downloads, hide ads and more …

健康的なMVVM 書いてますか? ~MVVMアンチパターン集~

健康的なMVVM 書いてますか? ~MVVMアンチパターン集~

Health Swift Meetup (http://finc-swift.connpass.com/event/29901/) の発表資料です。

takasek

April 27, 2016
Tweet

More Decks by takasek

Other Decks in Programming

Transcript

  1. .PEFM 7JFX.PEFM 7JFX %BUB #JOEJOH $PNNBOET ɹ%BUB#JOEJOHͷ࣮ݱͷͨΊʹ͸ɺJ04ͷ৔߹ ɹɹ'31ϥΠϒϥϦ 3Y4XJGU 3FBDUJWF$PDPB

    ΍ ɹɹσʔλόΠϯσΟϯάϥΠϒϥϦ 4XJGU#POE ͷ ɹɹαϙʔτ͕ඞཁ ɹ ˞'J/$Ͱ͸ݱࡏ4XJGU#POEΛར༻
  2. 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΁ͷࢀরΛ࣋ͬͯɺ௚઀ૢ࡞͢Δ
  3. 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 վળྫ
  4. ࠞઢ͍ͯ͠Δ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Λ ड͚औΔ
  5. class MyViewModel { let text = Observable<String>("") let textLength =

    Observable<Int>(0) } vm.text.value = "ͳΜ͔௕͍ςΩετ" vm.text // "ͳΜ͔௕͍ςΩετ" vm.textLength // 0 ←!!?!!? Ψϥεͷ7JFX.PEFM ঱ঢ় յΕͦ͏ͳ0CTFSWBCMF͹͔ΓूΊͯ͠·͏
  6. 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-FOHUI͸NBQ USBOTGPSNJOHPQFSBUPS Λ௨͚ͩ͢ͷ ɹ$PMEͳଘࡏʹ͠ɺ੔߹ੑΛอূ એݴతʹهड़Ͱ͖ͨʂ
  7. 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 ͲͪΒ͕มߋ͞Εͯ΋ ྆ํΛ࢖ͬͯߋ৽ॲཧΛ ߦ͍͍ͨʂ
  8. ઉ଍Βͣͳ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͕ λϓϧͰ౉ͬͯ͘Δ
  9. 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ଆʹঢ়ଶ΍৚݅෼ذ͕͋Δ
  10. ؂ಜෆߦಧͳ7JFX.PEFM ॲํᝦ ʮ7JFX͸7JFX.PEFMͷӨʯΛ పఈͤ͞Δ class MyView { func awakeFromNib() {

    viewModel.title.observe { ... } viewModel.image.observe { ... } viewModel.detail.observe { ... } } } 7JFX͸Կ΋൑அΛߦΘͣɺ 7JFX.PEFMͷঢ়ଶΛ ໧ʑͱ6*ʹ൓өͤ͞Δ 7JFX.PEFM͸ɺ 7JFXΛ࠶ߏ੒Ͱ͖Δ͚ͩͷ ঢ়ଶ৘ใΛอ࣋͢Δ
  11. ਆܦ࣭ͳ7JFX.PEFM ॲํᝦ 0CTFSWBCMF7PJE class MyViewModel { let isUpdated = Observable<Void>()

    private func didSomething() { isUpdated.next() } } 81' 8JOEPXT1SFTFOUBUJPO'PVOEBUJPO ʹ͸ .FTTFOHFSͱ͍͏֓೦͕͋Δ
 7JFX.PEFM͕Πϕϯτͷൃߦͱ͍͏ܗͰ7JFXʹ௨஌͢Δ࢓૊Έ ղܾ͍ͨ͠໰୊͸ಉ͡ʜ ͩͱࢥ͏Μ͚ͩͲɺ 81'ͷ஌ݟ͕ͳ͍ͷͰ ؒҧͬͯͨΒ͢Έ·ͤΜʜ ͱΓ͋͑ͣ 0CTFSWBCMF7PJE͸ศརͰ͢