この記事はSafie Engineers' Blog! Advent Calendar 21日目の記事です
はじめに
Hello~ モバイルグループのアダムです。 今年も誕生日に記事を出せて嬉しいです!🎅
最近自分がはまっているモバイルのアーキテクチャの遊びについて紹介させてください!
今回の遊びの環境:
Xcode: 16.2
Minimum Target: 17.0
Swift: 6
Concurrency: Strict
MVVM
将来的に理想なアーキテクチャを行うならどんな感じで実装するのか?をやってみました。
今まで開発に参加していたアプリはほとんどMVVMだったので、最新のSwiftUIで実装した場合どんな形になるんだろう?🤔
オンメモリーのCacheを持つRepositoryがある場合どんな形で作るのか?
そのために今回どんな感じで考えたかを紹介させて〜
もしこんな方法おすすめ、こちらの方がベターっていうのがあったらこちら→@monolithic_adam or monolithic-adam.bsky.social にPOSTお願いします!
Environment
一旦例のためカウントを持つRepositoryとViewModelがincrementするUseCaseを用意します
Repository
@Observable
にして何かの変更があった場合Viewが再描画される
@Observable final class TestRepository { var count: Int = 0 }
ViewModel
ViewModelにシンプルなUseCaseを用意、Repositoryに最新の状態をアップデートできるfunc
を用意します
struct TestViewModel { let repository: TestRepository func increment() { repository.count += 1 } }
App/Scope
今回のRepositoryがアプリスコープのため、Appの方でinit
・.environment
にセットする
@main struct TestProjectApp: App { @State private var testRepository = TestRepository() var body: some Scene { WindowGroup { ContentView() .environment(testRepository) } } }
View
こちらが迷いポイント1です!
RepositoryがEnvironmentの方で設定しているので、どうやってViewModelへ渡すのかを迷っています・・・
Environmentはinit時にまだ存在しないのでparentから渡すのか、ViewModelを.environment
にセットして、observeすべきかも?
ま、一旦parentから渡す感じで実装してみましょう!
struct ContentView: View { @Environment(TestRepository.self) var repository: TestRepository let viewModel: TestViewModel init(repository: TestRepository) { self.viewModel = TestViewModel(repository: repository) } }
結局App側で二重に渡している感じになってしまう
@main struct TestProjectApp: App { @State private var testRepository = TestRepository() var body: some Scene { WindowGroup { ContentView(repository: testRepository) .environment(testRepository) } } }
最後に状態変化を見れるよう、シンプルにcountを表示させるTextとincrementできるボタンを用意して完成!
var body: some View { VStack { Text("Current Count \(repository.count)") Button { viewModel.increment() } label: { Text("Increment") } } .padding() }
結果
まとめ
- View -> ViewModelにRepository渡すことがEnvironmentをちゃんと活用できていないな〜
- 画面遷移する時にどうせ次のビューを渡さないといけなくなるので、あまりEnvironmentにセットする意味がない
init
時は気にしなくて良くなるViewModelをEnvironmentにした方が綺麗になる
理想はこうなるかな〜
おわりに
モバイルチームでは、このように多様な環境で世界に向けたアプリをともに開発する仲間を募集しています!
open.talentio.com