『ラクマ x STORES LTイベント ~ iOS開発の裏側 ~』での登壇資料 https://hey.connpass.com/event/236189/
ラクマでのSwiftUI導⼊⽅針とTips@darquroRakuten Group, Inc.
View Slide
2About Me@darquroラクマMobile Application Development Group Manager/ iOS Engineer
3Table of Contents• ラクマでのSwiftUI導⼊⽅針• SwiftUIでハマったこと• SwiftUI TipsTarget既存のUIKitベースのアプリにこれからSwiftUI導⼊していく⼈向け。※普段からSwiftUIで開発している⼈には物⾜りないかも 🙇
4🗼ラクマでのSwiftUI導⼊⽅針
5SwiftUI導⼊• 2021/2〜徐々に導⼊• 画⾯全体もあれば、⼀部コンポーネントのみなど• 追加読み込み(ページング)が不要(LazyVStackではなくListで済む)• 複雑な状態管理が不要という簡単な画⾯から移⾏🗼ラクマでのSwiftUI導⼊⽅針
6ArchitectureViewController Presenter UseCaseAPIClientsDataStoresRepositoriesSwiftUI View ViewModel UseCase Use APIClient directoryUse RepositoryApplication Lifecycle UpdateUIKit(MVP)SwiftUI(MVVM)Presentation LayerDomain LayerEntitiesSystemUser🗼ラクマでのSwiftUI導⼊⽅針
7ViewModel ProtocolViewModel Protocolとしてトレタさんのブログを参考にさせていただきました 🙏https://tech.toreta.in/entry/2019/12/24/104612🗼ラクマでのSwiftUI導⼊⽅針
8ViewModel ProtocolMVVMアーキテクチャは、単⽅向Bindingと双⽅向Bindingの概念があるが、SwiftUI+Combine標準APIでは制約はない。Binding⽅向の制約を設けることで、コードの⾒通しを良くする。🗼ラクマでのSwiftUI導⼊⽅針
9ViewModelViewViewModelObject.input• View Lifecycleによる状態更新• User Actionによる状態更新🗼ラクマでのSwiftUI導⼊⽅針
10ViewModelViewViewModelObject.binding• ViewとViewModel双⽅のデータ更新🗼ラクマでのSwiftUI導⼊⽅針
11ViewModelViewViewModelObject.output• Fetchされたデータによる画⾯更新• Status変更による画⾯更新🗼ラクマでのSwiftUI導⼊⽅針
12💣SwiftUIでハマったところ
13iOS13/iPadOS13のサポートは切ろう😇• TextFieldのキーボード⼊⼒まわりの挙動がおかしい• 謎クラッシュ• 標準コンポーネントが⾜りない• Combineのqueueを跨いぐと処理がおかしいなどなどiOS13でSwiftUIを使うのは危険💣SwiftUIでハマったところ
14Previewがエラーになって時間ばかり取られる 🤯Device modelを定義しておくと便利👍📱おかしいな…なんか変だなぁ…と感じたら、• エディタを全部閉じる• Xcode再起動• Clean Build• Emulatorの起ち上げ直し• DerivedData削除最後は諦めてEmulatorで確認💣SwiftUIでハマったところちなみに…
15if statementを多⽤しない⚠Xcodeのcode completionがぶっ壊れてまともにコードが書けなくなる 🥺💣SwiftUIでハマったところViewModelでstateのようなenumで条件分岐しようとすると…
16if #available() をViewModifierで使⽤しない💥Exception Type: EXC_BAD_ACCESS (SIGSEGV)Thread 0 name: Dispatch queue: com.apple.main-threadThread 0 Crashed:8 SwiftUI 0x00000001a07f2160 partial apply for closure#1 in ModifierBodyAccessor.updateBody+ 6332768 (of:changed:) + 289 SwiftUI 0x00000001a0814364 closure#1 in BodyAccessor.setBody+ 6472548 (_:) + 4410 SwiftUI 0x00000001a07f1a64ModifierBodyAccessor.updateBody+ 6330980 (of:changed:) + 144011 SwiftUI 0x00000001a08144a8StaticBody.updateValue+ 6472872 () + 20812 SwiftUI 0x00000001a0517764partial apply for implicit closure #2 in implicit closure#1 in closure #1 in closure #1 in Attribute.init+ 3340132 (_:) + 28Xcode13.2 で謎クラッシュが発⽣する。しかもDebugビルドでは発⽣せず、Releaseビルドのみ起こる。@available()でView単位の出し分けにすることで回避https://developer.apple.com/forums/thread/697070💣SwiftUIでハマったところ
17🎩 🪄SwiftUI Tips
18ViewDidLoadModifier⚡標準だとonAppearしかないので、deta fetch系処理を⼊れてしまうと画⾯⾏き来する度にリクエストが⾛る。ViewDidLoadModifierを作ることで、画⾯表⽰の初回のみ呼ばれるイベントを作る。画⾯表⽰の初回のみ呼ばれる🎩 🪄SwiftUI Tips
19Alert Binding ⚡iOS15からalertのメソッドが変わった。ただこれらだと、状態とメッセージを別々にbindする必要が出てきて、ViewModel側が冗⻑になってくる。iOS14 iOS15🎩 🪄SwiftUI Tips
20Alert Binding ⚡iOS14にはIdentifiableをbindしてalertを出せるメソッドがあった。しかしiOS15ではなくなった。iOS14🎩 🪄SwiftUI Tips
21Alert Binding ⚡iOS14とiOS15それぞれの互換性を保ち、ViewModelから状態とメッセージをまとめてViewに変更を通知させたい。🧐🎩 🪄SwiftUI Tips
22Alert Binding ⚡①ObservableObjectを使ったclassを作成。iOS14とiOS15それぞれの互換性を保ち、ViewModelから状態とメッセージをまとめてViewに変更を通知させたい。🎩 🪄SwiftUI Tips
23iOS15iOS14Alert Binding ⚡②ViewModifierを作成し、iOS15以降とそれ以前の実装を書く。ViewModifier内でif #availableで分岐するとcrashする問題があるのでViewModifier単位で分ける。iOS14とiOS15それぞれの互換性を保ち、ViewModelから状態とメッセージをまとめてViewに変更を通知させたい。🎩 🪄SwiftUI Tips
24Alert Binding ⚡③Viewのextensionを⽤意。iOS14とiOS15それぞれの互換性を保ち、ViewModelから状態とメッセージをまとめてViewに変更を通知させたい。🎩 🪄SwiftUI Tips
25ViewModelViewAlert Binding ⚡ViewModelからメッセージ送るだけ実装が完結になるiOS14とiOS15それぞれの互換性を保ち、ViewModelから状態とメッセージをまとめてViewに変更を通知させたい。🎩 🪄SwiftUI Tips
26ViewodelAlert Binding ⚡ iOS14とiOS15それぞれの互換性を保ち、ViewModelから状態とメッセージをまとめてViewに変更を通知させたい。④同じ要領で、.destructiveボタンと.cancelボタンの確認アラートも作成しておくと汎⽤的に使える。🎩 🪄SwiftUI Tips
27さいごに
28⾊々⼤変だけど、
29やっていくしかないですね💪
Thank you 🥳