Skip to content

Commit b097cac

Browse files
authored
Merge pull request #86 from android/mlykotom/export-viewmodel
Scope ViewModels with StateObject + export ViewModel dependency
2 parents f5e89fa + d75c947 commit b097cac

File tree

6 files changed

+27
-43
lines changed

6 files changed

+27
-43
lines changed
Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,19 @@
11
import SwiftUI
22
import shared
33

4-
/// A ViewModelStoreOwner specifically for iOS.
5-
/// This is used with from iOS with Kotlin Multiplatform (KMP).
6-
class IOSViewModelStoreOwner: ObservableObject, SwiftViewModelStoreOwner {
4+
/// A ViewModelStoreOwner specifically for iOS to be an ObservableObject.
5+
class IOSViewModelStoreOwner: ObservableObject, ViewModelStoreOwner {
76

8-
var viewModelStore: Lifecycle_viewmodelViewModelStore =
9-
Lifecycle_viewmodelViewModelStore()
7+
var viewModelStore = ViewModelStore()
108

119
/// This function allows retrieving the androidx ViewModel from the store.
12-
func viewModel<T: Lifecycle_viewmodelViewModel>(
10+
func viewModel<T: ViewModel>(
1311
key: String? = nil,
14-
factory: Lifecycle_viewmodelViewModelProviderFactory,
15-
extras: Lifecycle_viewmodelCreationExtras? = nil
12+
factory: ViewModelProviderFactory,
13+
extras: CreationExtras? = nil
1614
) -> T {
1715
do {
18-
return try viewModelStore.getViewModel(
16+
return try viewModel(
1917
modelClass: T.self,
2018
factory: factory,
2119
key: key,
@@ -26,7 +24,13 @@ class IOSViewModelStoreOwner: ObservableObject, SwiftViewModelStoreOwner {
2624
}
2725
}
2826

27+
/// This can be called from outside when using the `ViewModelStoreOwnerProvider`
2928
func clear() {
3029
viewModelStore.clear()
3130
}
31+
32+
/// This is called when this class is used as a `@StateObject`
33+
deinit {
34+
viewModelStore.clear()
35+
}
3236
}

Fruitties/iosApp/iosApp/ui/CartView.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import shared
2020

2121
struct CartView: View {
2222
/// Injects the `IOSViewModelStoreOwner` from the environment, which manages the lifecycle of `ViewModel` instances.
23-
@EnvironmentObject var viewModelStoreOwner: IOSViewModelStoreOwner
23+
@StateObject var viewModelStoreOwner = IOSViewModelStoreOwner()
2424

2525
/// Injects the `AppContainer` from the environment, providing access to application-wide dependencies.
2626
@EnvironmentObject var appContainer: ObservableValueWrapper<AppContainer>

Fruitties/iosApp/iosApp/ui/ContentView.swift

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,7 @@ struct ContentView: View {
3939
value in
4040
HStack {
4141
NavigationLink {
42-
ViewModelStoreOwnerProvider {
43-
FruittieScreen(fruittie: value)
44-
}
42+
FruittieScreen(fruittie: value)
4543
} label: {
4644
FruittieView(fruittie: value)
4745
}
@@ -62,9 +60,7 @@ struct ContentView: View {
6260
.toolbar {
6361
ToolbarItem(placement: .navigationBarTrailing) {
6462
NavigationLink {
65-
ViewModelStoreOwnerProvider {
66-
CartView()
67-
}
63+
CartView()
6864
} label: {
6965
Observing(mainViewModel.homeUiState) { homeUIState in
7066
let total = homeUIState.cartItemCount

Fruitties/iosApp/iosApp/ui/FruittieScreen.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import SwiftUI
1919
import shared
2020

2121
struct FruittieScreen: View {
22-
@EnvironmentObject var viewModelStoreOwner: IOSViewModelStoreOwner
22+
@StateObject var viewModelStoreOwner = IOSViewModelStoreOwner()
2323
@EnvironmentObject var appContainer: ObservableValueWrapper<AppContainer>
2424
let fruittie: Fruittie
2525

Fruitties/shared/build.gradle.kts

Lines changed: 9 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -50,26 +50,17 @@ kotlin {
5050
// A step-by-step guide on how to include this library in an XCode
5151
// project can be found here:
5252
// https://developer.android.com/kotlin/multiplatform/migrate
53-
val xcfName = "shared"
5453

55-
iosX64 {
56-
binaries.framework {
57-
baseName = xcfName
54+
listOf(
55+
iosX64(),
56+
iosArm64(),
57+
iosSimulatorArm64(),
58+
).forEach {
59+
it.binaries.framework {
60+
export(libs.androidx.lifecycle.viewmodel)
61+
baseName = "shared"
5862
}
5963
}
60-
61-
iosArm64 {
62-
binaries.framework {
63-
baseName = xcfName
64-
}
65-
}
66-
67-
iosSimulatorArm64 {
68-
binaries.framework {
69-
baseName = xcfName
70-
}
71-
}
72-
7364
// Source set declarations.
7465
// Declaring a target automatically creates a source set with the same name. By default, the
7566
// Kotlin Gradle Plugin creates additional source sets that depend on each other, since it is
@@ -90,7 +81,7 @@ kotlin {
9081
implementation(libs.ktor.client.content.negotiation)
9182
implementation(libs.ktor.serialization.kotlinx.json)
9283
implementation(libs.skie.annotations)
93-
implementation(libs.androidx.lifecycle.viewmodel)
84+
api(libs.androidx.lifecycle.viewmodel)
9485
implementation(libs.androidx.paging.common)
9586
implementation(libs.androidx.room.runtime)
9687
implementation(libs.sqlite.bundled)

Fruitties/shared/src/iosMain/kotlin/com/example/fruitties/di/viewmodel/ViewModelStoreUtil.kt

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package com.example.fruitties.di.viewmodel
22

33
import androidx.lifecycle.ViewModel
44
import androidx.lifecycle.ViewModelProvider
5-
import androidx.lifecycle.ViewModelStore
65
import androidx.lifecycle.ViewModelStoreOwner
76
import androidx.lifecycle.viewmodel.CreationExtras
87
import kotlinx.cinterop.BetaInteropApi
@@ -18,7 +17,7 @@ import kotlin.reflect.KClass
1817
@Suppress("unused") // Android Studio is not aware of iOS usage.
1918
@OptIn(BetaInteropApi::class)
2019
@Throws(IllegalStateException::class)
21-
fun ViewModelStore.getViewModel(
20+
fun ViewModelStoreOwner.viewModel(
2221
modelClass: ObjCClass,
2322
factory: ViewModelProvider.Factory,
2423
key: String?,
@@ -30,9 +29,3 @@ fun ViewModelStore.getViewModel(
3029
val provider = ViewModelProvider.create(this, factory, extras ?: CreationExtras.Empty)
3130
return key?.let { provider[key, vmClass] } ?: provider[vmClass]
3231
}
33-
34-
/**
35-
* The ViewModelStoreOwner isn't used anywhere in the project, therefore it's not visible for Swift by default.
36-
*/
37-
@Suppress("unused")
38-
interface SwiftViewModelStoreOwner : ViewModelStoreOwner

0 commit comments

Comments
 (0)