Slide 1

Slide 1 text

No content

Slide 2

Slide 2 text

                              ・Rakuten Group, Inc                   ・Rakuma        ・iOS Developer    ・Developer Relations                              ・Twitter:@hcrane14

Slide 3

Slide 3 text

目次
 序章 SwiftUIに対応しよう
 - ラクマのアプリとリファクタリング 
 
 1章 SwiftUIの導入ライン
 - SwiftUIのデメリット
 
 2章 UIKitからSwiftUIへの移行
 - アーキテクチャー問題
 - 双方向のデータフロー実装
 - 画面のみを移行するケース
 3章 UIKitと画面遷移
 - UIHostingControllerの役割
 - Coordinatorパターンとその拡張 
 - FlowControllerについて
 
 終章
 - 開発のベストプラクティス
 
 その他・参考文献


Slide 4

Slide 4 text

No content

Slide 5

Slide 5 text

プロダクトのリファクタリング
 しっかりとやってますか?


Slide 6

Slide 6 text

No content

Slide 7

Slide 7 text

今年で10周年のアプリ
 Objective-Cから悲願のSwift対応!


Slide 8

Slide 8 text

100%
 66%
 2020/10
 2022/08
 Rakuma iOS App - Swift Percentage 


Slide 9

Slide 9 text

次は乗り遅れないために...
 高まるSwiftUIの機運


Slide 10

Slide 10 text

現状は...


Slide 11

Slide 11 text

Rakuma iOS App - UIHostingController Percentage 
 ※1 2022/7 時点
 ※2 画面数の割合ではないので注意


Slide 12

Slide 12 text

どのようにSwiftUIを
 UIKitに入れていくのが良いの?


Slide 13

Slide 13 text

No content

Slide 14

Slide 14 text

導入ライン...


Slide 15

Slide 15 text

SwiftUIで無理なく実装可能な画面


Slide 16

Slide 16 text

- 1画面単位で導入する
 - 継続して動的にコンテンツが増えない
 - カスタムViewを作成する必要がない
 ※ 厳密に準拠しているわけではない。 


Slide 17

Slide 17 text

理由①


Slide 18

Slide 18 text

iOSDC2021「Compositional Layoutsで実現する疎結合な実装 」より


Slide 19

Slide 19 text

対応が困難なUI達


Slide 20

Slide 20 text

Example
 Design for iPad


Slide 21

Slide 21 text

Example
 Design for List Separator 


Slide 22

Slide 22 text

WWDC2022で発表された新しいAPI


Slide 23

Slide 23 text

iOS16+ / NavigationStack 
 Declaration
 Example
 Quote: https://developer.apple.com/documentation/swiftui/navigationstack 


Slide 24

Slide 24 text

iOS16+ / Grid & GridRow 
 Quote: https://developer.apple.com/documentation/swiftui/grid?changes=_5 


Slide 25

Slide 25 text

少しずつ改善されてる!


Slide 26

Slide 26 text

けど、本格運用は2年後くらい...


Slide 27

Slide 27 text

理由②


Slide 28

Slide 28 text

SwiftUIではUIが不十分


Slide 29

Slide 29 text

じゃあ作る?


Slide 30

Slide 30 text

Quote: https://qiita.com/noppefoxwolf/items/5b65ab3d62acd83a79cc 


Slide 31

Slide 31 text

独自にカスタマイズした結果...
 - 後々に負債になりうるもの
 - メンテコストがかかるもの
 は作らない方が良い


Slide 32

Slide 32 text

例えば...


Slide 33

Slide 33 text

iOS15+ / refreshable 
 Declaration
 Example
 Quote: https://developer.apple.com/documentation/SwiftUI/View/refreshable(action:) 


Slide 34

Slide 34 text

ScrollViewでは使えないので拡張する


Slide 35

Slide 35 text

Example
 `refreshable` extension for Scrollview 


Slide 36

Slide 36 text

iOS14では使えないので拡張する


Slide 37

Slide 37 text

Example
 `refreshable` extension for iOS14 
 View Wrapper 
 UIKit Wrapper 
 ScrollView Wrapper 


Slide 38

Slide 38 text

No content

Slide 39

Slide 39 text

次のアップデートで...


Slide 40

Slide 40 text

Quote: https://twitter.com/clarko/status/1552383186604216321 


Slide 41

Slide 41 text

No content

Slide 42

Slide 42 text

- UIKitにあるけどSwiftUIにないものは積極的に作らない
  → 今後ネイティブのAPIで提供される可能性が高い
 
 - ないものは作るしかない
  → アプリ固有でユーザー体験を提供するための機能
  ex カルーセル、カメラ、動画、広告 etc. 


Slide 43

Slide 43 text

No content

Slide 44

Slide 44 text

どこまで移行するのか問題


Slide 45

Slide 45 text

低
 難易度
 View + 遷移
 View + ロジック
 View 全体
 View パーツ
 高


Slide 46

Slide 46 text

UIKitの資産を生かしつつ移行したい


Slide 47

Slide 47 text

低
 難易度
 View + 遷移
 View + ロジック
 View 全体
 View パーツ
 高
 選択したライン


Slide 48

Slide 48 text

アーキテクチャーの問題


Slide 49

Slide 49 text

現在採用しているアーキテクチャー


Slide 50

Slide 50 text

UseCase
 Repository
 DataStore
 APIClient
 UIKit
 MVP + Clean Architecture 
 ViewController 
 Presenter
 Presenter Protocol 
 ViewController Protocol
 UseCase Protocol 
 Repository Protocol 
 Data Layer Protocol


Slide 51

Slide 51 text

SwiftUIに適していない


Slide 52

Slide 52 text

UseCase
 Repository
 DataStore
 APIClient
 UIKit
 MVP + Clean Architecture 
 ViewController 
 Presenter
 UseCase
 Repository
 DataStore
 APIClient
 Presenter Protocol 
 ViewController Protocol
 Unidirectional Data Flow

Slide 53

Slide 53 text

Presenter
 ViewController 
 Example
 Unidirectional Data Flow 
 ※ 簡易な説明のため initialize は省略 


Slide 54

Slide 54 text

Presenter
 ViewController 
 Input
 Output
 Example
 Unidirectional Data Flow 


Slide 55

Slide 55 text

単一方向だけで問題なかった


Slide 56

Slide 56 text

SwiftUIは双方向のデータフローが必須


Slide 57

Slide 57 text

例えば...


Slide 58

Slide 58 text

Example
 Bidirectional Binding View 
 SwiftUI - Textfield 


Slide 59

Slide 59 text

Viewによっては双方向な実装を強制される


Slide 60

Slide 60 text

SwiftUIは違うアーキテクチャーを検討する


Slide 61

Slide 61 text

- The Composable Architecture(TCA)
 - RIBs
 - ReSwift
 - VIPER
 - MVVM
 etc.


Slide 62

Slide 62 text

ここで今一度考えて欲しい


Slide 63

Slide 63 text

プロダクトのリファクタリング
 しっかりとやってますか?


Slide 64

Slide 64 text

リアーキテクチャーしたものを
 全ての画面にちゃんと実装してますか?


Slide 65

Slide 65 text

- アーキテクチャーを実装しきった話はほぼ聞かない
 - アーキテクチャーを入れて満足している
 - 継続的なメンテがされていない
 - 導入した人は数年でいなくなっている
 - さらにリアーキテクチャーしてごちゃごちゃ


Slide 66

Slide 66 text

チームや開発の状況を見て
 一番適したもの検討して導入するべき


Slide 67

Slide 67 text

チームや開発の状況としては...
 - UIKitの資産を生かしつつ対応可能
 - 双方向のデータフローを許容できる
 これを満たすものを導入したい


Slide 68

Slide 68 text

ViewController 
 Presenter
 UseCase
 Repository
 DataStore
 APIClient
 UIKit to SwiftUI
 
 UIKit
 SwiftUI
 ❔


Slide 69

Slide 69 text

UseCase
 Repository
 DataStore
 APIClient
 ViewController 
 Presenter
 UseCase
 Repository
 DataStore
 APIClient
 Domain / Data Layer

Slide 70

Slide 70 text

View
 ???
 ViewController 
 Presenter
 UseCase
 Repository
 DataStore
 APIClient
 UseCase
 Repository
 DataStore
 APIClient
 NEW
 NEW
 Presentation Layer

Slide 71

Slide 71 text

MVVMの採用
 (+ Clearn Architecture)


Slide 72

Slide 72 text

View
 ???
 UseCase
 Repository
 DataStore
 APIClient
 SwiftUI
 MVVM + Clean Architecture 
 NEW
 ViewModel
 NEW


Slide 73

Slide 73 text

その他の要因
 - MVVMの経験者が複数人在籍しており学習コストが低い
 - 複雑な状態管理を必要する画面がいくつかしかない(not TCA)
 - RouterとSwiftUIの相性が悪い(not VIPER)


Slide 74

Slide 74 text

アプリのアーキテクチャー全体像


Slide 75

Slide 75 text

Quote: https://qiita.com/karamage/items/8a9c76caff187d3eb838 


Slide 76

Slide 76 text

アーキテクチャーの共存


Slide 77

Slide 77 text

Quote: https://qiita.com/karamage/items/8a9c76caff187d3eb838 


Slide 78

Slide 78 text

どのアーキテクチャーがベストとかはない


Slide 79

Slide 79 text

チームや開発の状況を見て
 一番適したもの検討して導入するべき
 (大事なことなので2回目)


Slide 80

Slide 80 text

SwiftUIにおけるMVVMの実装は?


Slide 81

Slide 81 text

既存のスタンダードな実装方法


Slide 82

Slide 82 text

No content

Slide 83

Slide 83 text

※ 簡易な説明のため一部は省略しています 


Slide 84

Slide 84 text

※ 簡易な説明のため一部は省略しています 


Slide 85

Slide 85 text

ObservableObjectの仕様で
 SwiftUI上では抽象化したものは使えない
 ※ する方法はあるが、実装を縛れなくなる 


Slide 86

Slide 86 text

他の方法で実装を管理する


Slide 87

Slide 87 text

Example - ViewModel 
 ※ 簡易な説明のため一部は省略しています 


Slide 88

Slide 88 text

Example - View


Slide 89

Slide 89 text

ボイラーテンプレートを
 いい感じにまとめたい


Slide 90

Slide 90 text

Quote: https://tech.toreta.in/entry/2019/12/24/104612 
 Example1
 SwiftUIとCombineを使ったMVVMの実装 


Slide 91

Slide 91 text

Example2
 marty-suzuki / AnyObservableObject 
 Quote: https://github.com/marty-suzuki/AnyObservableObject 


Slide 92

Slide 92 text

現状は...


Slide 93

Slide 93 text

2020/10
 2022/08
 Rakuma iOS App - Architecture Percentage 
 MVC MVC MVP MVVM MVP

Slide 94

Slide 94 text

もう少し軽めにSwiftUIを導入したい場合


Slide 95

Slide 95 text

低
 難易度
 View + 遷移
 View + ロジック
 View 全体
 View パーツ
 高
 軽めに導入ライン


Slide 96

Slide 96 text

画面のみSwiftUIにする


Slide 97

Slide 97 text

Quote: https://techlife.cookpad.com/entry/2021/01/18/kaimono-swift-ui 


Slide 98

Slide 98 text

Quote: https://tech.toreta.in/entry/2019/12/24/104612 
 VIPER architecture


Slide 99

Slide 99 text

SwiftUI + VIPER architecture


Slide 100

Slide 100 text

UIKitの資産をそのまま持ってこれる


Slide 101

Slide 101 text

No content

Slide 102

Slide 102 text

画面遷移をどうするか


Slide 103

Slide 103 text

低
 難易度
 View + 遷移
 View + ロジック
 View 全体
 View パーツ
 高
 選択したライン


Slide 104

Slide 104 text

UIHostingControllerを親画面とした画面遷移


Slide 105

Slide 105 text

Bad


Slide 106

Slide 106 text

Good


Slide 107

Slide 107 text

UIViewController UIViewController UIHostingController SwiftUI View ViewModel Domain / Data Layer UIHostingController SwiftUI View ViewModel Domain / Data Layer Good
 Bad


Slide 108

Slide 108 text

Caution 


Slide 109

Slide 109 text

UIHostingController SwiftUI View ViewModel Navigation Flow
 Next
 Previous
 Previous
 Next
 Domain / Data Layer

Slide 110

Slide 110 text

UIHostingController UIHostingController SwiftUI View ViewModel Processing Flow
 MVVM+α
 Domain / Data Layer Output
 Input
 Binding


Slide 111

Slide 111 text

UIHostingController SwiftUI View ViewModel Processing Flow
 ViewModel to UIHostingController 
 Output
 Initialize
 Domain / Data Layer Domain / Data Layer

Slide 112

Slide 112 text

簡単な例


Slide 113

Slide 113 text

※ 簡易な説明のため一部は省略しています 


Slide 114

Slide 114 text

No content

Slide 115

Slide 115 text

Output Initialize ※ 簡易な説明のため一部は省略しています 


Slide 116

Slide 116 text

もう少し踏み込んで実装したい場合


Slide 117

Slide 117 text

Coordinatorパターンによる実装


Slide 118

Slide 118 text

ViewController 
 ViewController 
 ViewController 
 ViewController 
 Coordinator Coordinator Pattern 


Slide 119

Slide 119 text

画面遷移のみを持つ
 UIHostingControllerとの相性が良い


Slide 120

Slide 120 text

UIHostingController SwiftUI View ViewModel Navigation Flow
 Next
 Previous
 Previous
 Next
 Domain / Data Layer

Slide 121

Slide 121 text

Coordinatorパターンの拡張


Slide 122

Slide 122 text

FlowControllerと画面遷移のコントロール


Slide 123

Slide 123 text

Quote: https://ocollet.com/2014/02/06/flow-controller/ 


Slide 124

Slide 124 text

> One of the first rules a developer learns is to separate the code handling the data and the user interface. The link between the data and UI is usually done in a controller, or, in iOS, a view controller. In most projects, view controllers are interconnected and can be very dependent with one another. That’s where the flow controller comes in. It serves as a link between view controllers. It’s the brain of the app.
 Quote: https://ocollet.com/2014/02/06/flow-controller/ 


Slide 125

Slide 125 text

Quote: https://github.com/onmyway133/blog/issues/106 


Slide 126

Slide 126 text

UIHostingControllerで実装する


Slide 127

Slide 127 text

Quote: https://qiita.com/hugehoge/items/b28f134bc4806d584892 


Slide 128

Slide 128 text

将来的に完全なSwiftUIに寄せたい場合は
 コストになりかねないかも...


Slide 129

Slide 129 text

No content

Slide 130

Slide 130 text

2022年において
 UIKitの中でSwiftUIを開発していく
 ベストプラクティスは何?


Slide 131

Slide 131 text

- SwiftUIで無理なく実装可能な画面のみを対応
 - 画面のみ または 画面+ロジック までをSwiftUIで実装
 - UIHostingControllerを起点として画面遷移


Slide 132

Slide 132 text

Thank you for listening!


Slide 133

Slide 133 text

その他・参考文献


Slide 134

Slide 134 text

iOSDC2021 パンフレット 
 「10年目のアプリ リファクタリングと開発」 


Slide 135

Slide 135 text

Quote: https://speakerdeck.com/darquro/rakuma-swiftui-introduction-policy-and-tips 


Slide 136

Slide 136 text

crane-hiromu / SwiftUI-MVVM-HostingController 
 Quote: https://github.com/crane-hiromu/SwiftUI-MVVM-HostingController 


Slide 137

Slide 137 text

Quote: https://qiita.com/shiz/items/4a828dc8e4eb0c96d397 


Slide 138

Slide 138 text

Quote: https://qiita.com/hugehoge/items/b28f134bc4806d584892