### Usage Example for launch Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/api-reference-viewmodelscope.md Example demonstrating how to use the launch extension function to start a coroutine within the ViewModelScope. ```kotlin class DataViewModel: ViewModel() { private val _data = MutableStateFlow(viewModelScope, listOf()) val data = _data.asStateFlow() init { viewModelScope.launch { val items = fetchData() _data.value = items } } } ``` -------------------------------- ### SwiftUI View Setup Using Environment Injection Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/configuration-swift.md Example of injecting a ViewModel into the environment and accessing it in a child view. ```swift struct RootView: View { @StateViewModel var viewModel = MyViewModel() var body: some View { ContentView() .environmentViewModel(viewModel) } } struct ContentView: View { @EnvironmentViewModel var viewModel: MyViewModel var body: some View { Text("Data: \(viewModel.data.value ?? "")") } } ``` -------------------------------- ### CocoaPods Setup Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/configuration-swift.md Alternative setup for CocoaPods users, specifying the repository and tag. ```ruby pod 'KMPObservableViewModelSwiftUI', git: 'https://github.com/rickclephas/KMP-ObservableViewModel.git', tag: 'v1.0.4' ``` -------------------------------- ### Basic Protocol Extension Setup Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/configuration-swift.md Setup to make all Kotlin ViewModels automatically conform to the ViewModel protocol. ```swift import KMPObservableViewModelCore import shared extension Kmp_observableviewmodel_coreViewModel: @retroactive ViewModel { } ``` -------------------------------- ### Complete Example Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/api-reference-swift-child-viewmodels.md Example of how to use a child ViewModel in a parent Swift view. ```swift import KMPObservableViewModelCore import shared // Parent view struct ParentView: View { @StateViewModel var parent = ParentViewModel() var body: some View { VStack { if let child = parent.childViewModel { ChildView(viewModel: child) } } } } // Extension to bridge Kotlin StateFlow property extension ParentViewModel { var childViewModel: ChildViewModel? { childViewModel(at: \.__childViewModel) } } ``` -------------------------------- ### Child ViewModel Setup in Kotlin Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/configuration-swift.md Example of defining a child ViewModel property in Kotlin using StateFlow. ```kotlin // Kotlin side @NativeCoroutinesRefinedState val childViewModel: StateFlow = MutableStateFlow(viewModelScope, null) ``` -------------------------------- ### Protocol Extension Setup with Observation Support (iOS 17+) Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/configuration-swift.md Setup to add Observable conformance for fine-grained change tracking on iOS 17+. ```swift import Observation import KMPObservableViewModelCore import shared extension Kmp_observableviewmodel_coreViewModel: @retroactive ViewModel { } extension Kmp_observableviewmodel_coreViewModel: @retroactive Observable { } ``` -------------------------------- ### Launch Coroutines (Kotlin) Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/quick-reference.md Example of launching coroutines within a ViewModel's scope. ```kotlin class DataViewModel: ViewModel() { fun loadData() { viewModelScope.launch { val data = fetchData() _data.value = data } } } ``` -------------------------------- ### @StateViewModel Usage Example Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/api-reference-swift-property-wrappers.md An example demonstrating how to use @StateViewModel in a SwiftUI View to manage a Kotlin ViewModel. ```swift import SwiftUI import KMPObservableViewModelSwiftUI import shared struct ContentView: View { @StateViewModel var viewModel = TimeTravelViewModel() var body: some View { VStack { Text("Time: \(viewModel.actualTime.value)") Button("Travel") { // Use viewModel } } } } ``` -------------------------------- ### Setup Swift Extension (Swift) Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/quick-reference.md Provides a Swift extension to make a Kotlin ViewModel conform to the Swift ViewModel protocol. ```swift import KMPObservableViewModelCore import shared extension Kmp_observableviewmodel_coreViewModel: @retroactive ViewModel { } ``` -------------------------------- ### Create your ViewModels Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/README.md Example of creating a ViewModel using KMP-ObservableViewModel, demonstrating the use of MutableStateFlow and stateIn. ```kotlin import com.rickclephas.kmp.observableviewmodel.ViewModel import com.rickclephas.kmp.observableviewmodel.MutableStateFlow import com.rickclephas.kmp.observableviewmodel.stateIn open class TimeTravelViewModel: ViewModel() { private val clockTime = Clock.time /** * A [StateFlow] that emits the actual time. */ val actualTime = clockTime.map { formatTime(it) } .stateIn(viewModelScope, SharingStarted.WhileSubscribed(), "N/A") private val _travelEffect = MutableStateFlow(viewModelScope, null) /** * A [StateFlow] that emits the applied [TravelEffect]. */ val travelEffect = _travelEffect.asStateFlow() } ``` -------------------------------- ### Protocol Extension Setup for Specific ViewModels Only Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/configuration-swift.md Setup to limit Observable conformance to specific ViewModels. ```swift import shared extension shared.MySpecificViewModel: Observable { } ``` -------------------------------- ### Version Management Example Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/configuration-kotlin.md Shows how to specify the KMP-ObservableViewModel library version in a Gradle dependencies block. ```kotlin dependencies { api("com.rickclephas.kmp:kmp-observableviewmodel-core:1.0.4") } ``` -------------------------------- ### Usage Example for async Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/api-reference-viewmodelscope.md Example demonstrating how to use the async extension function to launch an asynchronous operation and retrieve its result within the ViewModelScope. ```kotlin class UserViewModel: ViewModel() { private val _user = MutableStateFlow(viewModelScope, null) val user = _user.asStateFlow() fun loadUser(userId: String) { viewModelScope.launch { val userDeferred = viewModelScope.async { fetchUserFromNetwork(userId) } _user.value = userDeferred.await() } } } ``` -------------------------------- ### Basic SwiftUI Usage Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/configuration-swift.md Example of using the @StateViewModel property wrapper in a SwiftUI View. ```swift import SwiftUI import KMPObservableViewModelSwiftUI import shared struct ContentView: View { @StateViewModel var viewModel = MyViewModel() var body: some View { VStack { Text("Data: \(viewModel.data.value ?? "")") Button("Update") { viewModel.update() } } } } ``` -------------------------------- ### Usage Example for coroutineScope Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/api-reference-viewmodelscope.md Example demonstrating how to access and use the underlying CoroutineScope from ViewModelScope. ```kotlin class MyViewModel: ViewModel() { init { // Access the underlying CoroutineScope val scope = viewModelScope.coroutineScope scope.launch { // Coroutine is cancelled when ViewModel is destroyed } } } ``` -------------------------------- ### Constructor with CoroutineScope Usage Example Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/api-reference-viewmodel.md Example of creating a ViewModel with a custom CoroutineScope. ```kotlin val customScope = CoroutineScope(Job() + Dispatchers.Main) class MyViewModel: ViewModel(customScope) { // ... } ``` -------------------------------- ### Optional Child ViewModel Usage Example (Swift) Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/api-reference-swift-child-viewmodels.md Swift usage example for managing an optional child ViewModel. ```swift extension ParentViewModel { var childViewModel: ChildViewModel? { childViewModel(at: \.__childViewModel) } } ``` -------------------------------- ### Package.swift Dependency Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/configuration-swift.md Example of how to add KMP-ObservableViewModel to your Package.swift file. ```swift .package(url: "https://github.com/rickclephas/KMP-ObservableViewModel.git", from: "1.0.4") ``` -------------------------------- ### Usage Example for Projection Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/types.md Example demonstrating how to use the Projection struct with the '$' prefix for creating a two-way binding to a ViewModel property. ```swift @StateViewModel var viewModel: FormViewModel TextField("Name", text: $viewModel.name) // Creates a Binding through Projection ``` -------------------------------- ### Default Constructor Usage Example Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/api-reference-viewmodel.md Example of how to use the default constructor to create a ViewModel and initialize a MutableStateFlow. ```kotlin class MyViewModel: ViewModel() { val items = MutableStateFlow(viewModelScope, emptyList()) } ``` -------------------------------- ### macOS Specific Property Wrapper Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/configuration-swift.md Example of a property wrapper for macOS, specifying the deployment target. ```swift @available(macOS 11.0, *) @propertyWrapper public struct StateViewModel ``` -------------------------------- ### Optional Child ViewModel Usage Example (Kotlin) Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/api-reference-swift-child-viewmodels.md Kotlin usage example for managing an optional child ViewModel. ```kotlin class ParentViewModel: ViewModel() { private val _childViewModel: MutableStateFlow = MutableStateFlow(viewModelScope, null) val childViewModel: StateFlow = _childViewModel.asStateFlow() } ``` -------------------------------- ### Non-Optional Child ViewModel Usage Example (Swift) Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/api-reference-swift-child-viewmodels.md Swift usage example for managing a non-optional child ViewModel. ```swift extension ParentViewModel { var childViewModel: ChildViewModel { childViewModel(at: \.childViewModel) } } ``` -------------------------------- ### iOS Specific Property Wrapper Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/configuration-swift.md Example of a property wrapper for iOS, specifying the deployment target. ```swift @available(iOS 14.0, *) @propertyWrapper public struct StateViewModel ``` -------------------------------- ### Swift Extension Conformance Example Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/api-reference-swift-viewmodel.md Example of how to create a Swift extension to conform a Kotlin ViewModel to the ViewModel protocol for use with SwiftUI. ```swift import KMPObservableViewModelCore import shared // Your Kotlin shared module extension Kmp_observableviewmodel_coreViewModel: @retroactive ViewModel { } ``` -------------------------------- ### MutableStateFlow Usage Example Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/api-reference-stateflow.md An example demonstrating how to use the MutableStateFlow factory function within a ViewModel. ```kotlin import com.rickclephas.kmp.observableviewmodel.MutableStateFlow class CounterViewModel: ViewModel() { private val _count = MutableStateFlow(viewModelScope, 0) val count = _count.asStateFlow() fun increment() { _count.value++ } } ``` -------------------------------- ### Non-Optional Child ViewModel Usage Example (Kotlin) Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/api-reference-swift-child-viewmodels.md Kotlin usage example for managing a non-optional child ViewModel. ```kotlin class ParentViewModel: ViewModel() { val childViewModel: ChildViewModel = ChildViewModel() } ``` -------------------------------- ### Usage Example for isActive Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/api-reference-viewmodelscope.md Example demonstrating how to use the isActive property to safely perform operations within the ViewModelScope. ```kotlin class MyViewModel: ViewModel() { suspend fun loadData() { if (viewModelScope.isActive) { // Safe to use the scope } } } ``` -------------------------------- ### Xcode Setup Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/configuration-swift.md Add the KMP-ObservableViewModel package to your Xcode project via File > Add Packages. ```swift https://github.com/rickclephas/KMP-ObservableViewModel.git ``` -------------------------------- ### View Extension: environmentViewModel Usage Example Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/api-reference-swift-property-wrappers.md An example of how to use the .environmentViewModel() modifier to inject a ViewModel into the environment. ```swift let userViewModel = UserViewModel() AnyView( MyView() .environmentViewModel(userViewModel) ) ``` -------------------------------- ### Trace State Changes (Kotlin) Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/quick-reference.md A simple example of tracing state changes in a Kotlin ViewModel by logging state updates. ```kotlin class TracedViewModel: ViewModel() { private val _state = MutableStateFlow(viewModelScope, null) val state = _state.asStateFlow() private fun setState(value: Any?) { println("State changing to: $value") _state.value = value } } ``` -------------------------------- ### Subclassing ViewModels in Swift Example Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/api-reference-swift-viewmodel.md Example demonstrating how to subclass a Kotlin ViewModel in Swift and add SwiftUI-specific properties like @Published. ```swift import Combine import shared class MySwiftViewModel: shared.MyKotlinViewModel { @Published var isLoading: Bool = false } ``` -------------------------------- ### Constructor with CoroutineScope and AutoCloseable Resources Usage Example Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/api-reference-viewmodel.md Example of a ViewModel managed by a provided scope and resources. ```kotlin class ComplexViewModel(scope: CoroutineScope): ViewModel(scope, resource1, resource2) { // Both scope and resources are managed } ``` -------------------------------- ### stateIn Usage Example Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/api-reference-stateflow.md An example demonstrating how to use the stateIn extension function to convert a Flow into a StateFlow within a ViewModel. ```kotlin import com.rickclephas.kmp.observableviewmodel.stateIn import kotlinx.coroutines.flow.SharingStarted class DataViewModel: ViewModel() { private val dataFlow = fetchDataFlow() val data = dataFlow .map { formatData(it) } .stateIn( viewModelScope, SharingStarted.WhileSubscribed(), initialValue = null ) } ``` -------------------------------- ### With KMP-NativeCoroutines Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/api-reference-swift-child-viewmodels.md Example demonstrating the use of KMP-NativeCoroutines with child ViewModels. ```kotlin // Kotlin side class ParentViewModel: ViewModel() { @NativeCoroutinesRefinedState val childViewModels: StateFlow?> = MutableStateFlow(viewModelScope, null).asStateFlow() } ``` ```swift // Swift side extension ParentViewModel { var childViewModels: [ChildViewModel?]? { childViewModels(at: \.__childViewModels) } } ``` -------------------------------- ### viewModelScope Usage Example Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/api-reference-viewmodel.md Example of using viewModelScope to launch a coroutine for a timer in a ViewModel. ```kotlin class TimerViewModel: ViewModel() { init { viewModelScope.launch { while (isActive) { delay(1000) // Update state } } } } ``` -------------------------------- ### Optional Array of Optional Child ViewModels Usage Example (Swift) Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/api-reference-swift-child-viewmodels.md Swift usage example for managing an optional array of optional child ViewModels. ```swift extension ListParentViewModel { var items: [ItemViewModel?]? { childViewModels(at: \.items) } } ``` -------------------------------- ### Constructor with AutoCloseable Resources Usage Example Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/api-reference-viewmodel.md Example of a ViewModel managing a database connection that will be closed automatically. ```kotlin class DatabaseViewModel: ViewModel(dbConnection) { // dbConnection will be closed when onCleared() is called } ``` -------------------------------- ### Optional Array of Optional Child ViewModels Usage Example (Kotlin) Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/api-reference-swift-child-viewmodels.md Kotlin usage example for managing an optional array of optional child ViewModels. ```kotlin class ListParentViewModel: ViewModel() { val items: StateFlow?> = MutableStateFlow(viewModelScope, null).asStateFlow() } ``` -------------------------------- ### Combining Multiple Flows (Kotlin) Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/quick-reference.md Example of combining multiple Kotlin Flows into a single Flow using the `combine` operator. ```kotlin class MultiViewModel: ViewModel() { val combined = combine(flow1, flow2) { a, b -> Pair(a, b) } .stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null) } ``` -------------------------------- ### Using Expect/Actual for Platform-Specific Code Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/configuration-kotlin.md Provides an example of using expect/actual declarations to implement platform-specific ViewModel logic in Kotlin Multiplatform. ```kotlin // commonMain expect open class PlatformViewModel: ViewModel { fun platformSpecificFunction() } // androidMain actual open class PlatformViewModel: ViewModel() { actual override fun platformSpecificFunction() { // Android implementation } } // appleMain actual open class PlatformViewModel: ViewModel() { actual override fun platformSpecificFunction() { // Apple implementation } } ``` -------------------------------- ### ViewModel Property Wrappers Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/configuration-swift.md Examples of using different property wrappers (@StateViewModel, @EnvironmentViewModel, @ObservedViewModel) for ViewModels in SwiftUI. ```swift // ✓ For view-created ViewModels struct MyView: View { @StateViewModel var viewModel = MyViewModel() } // ✓ For dependency-injected ViewModels struct MyView: View { @EnvironmentViewModel var viewModel: MyViewModel } // ✓ For parent-provided ViewModels struct MyView: View { @ObservedViewModel var viewModel: MyViewModel } ``` -------------------------------- ### Extensions in Shared File Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/configuration-swift.md Example of defining ViewModel and Observable extensions in a shared file. ```swift // KMPObservableViewModel.swift - shared across app import KMPObservableViewModelCore import shared extension Kmp_observableviewmodel_coreViewModel: @retroactive ViewModel { } extension Kmp_observableviewmodel_coreViewModel: @retroactive Observable { } ``` -------------------------------- ### EnvironmentViewModel Usage Example Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/api-reference-swift-property-wrappers.md Demonstrates how to use @EnvironmentViewModel to access a ViewModel injected into the SwiftUI environment. ```swift import SwiftUI import KMPObservableViewModelSwiftUI import shared struct UserDetailsView: View { @EnvironmentViewModel var viewModel: UserViewModel var body: some View { Text("User: \(viewModel.user.value?.name ?? \"Unknown\")") } } struct RootView: View { @StateViewModel var viewModel = UserViewModel() var body: some View { UserDetailsView() .environmentViewModel(viewModel) } } ``` -------------------------------- ### Android ViewModel usage Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/README.md Example of using the ViewModel in an Android Fragment. ```kotlin import androidx.fragment.app.Fragment import androidx.fragment.app.viewModels class TimeTravelFragment: Fragment(R.layout.fragment_time_travel) { private val viewModel: TimeTravelViewModel by viewModels() } ``` -------------------------------- ### SwiftUI StateViewModel usage Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/README.md Example of using the @StateViewModel property wrapper in a SwiftUI View. ```swift import SwiftUI import KMPObservableViewModelSwiftUI import shared // This should be your shared KMP module struct ContentView: View { @StateViewModel var viewModel = TimeTravelViewModel() } ``` -------------------------------- ### Subclassing Kotlin ViewModel in Swift Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/README.md Example of subclassing a Kotlin ViewModel in Swift and using @Published. ```swift import Combine import shared // This should be your shared KMP module class TimeTravelViewModel: shared.TimeTravelViewModel { @Published var isResetDisabled: Bool = false } ``` -------------------------------- ### Cross-OS-Version Support Example Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/api-reference-swift-observable.md Demonstrates how to use Observation on iOS 17+ while falling back to ObservableObject on older versions. ```swift @EnvironmentViewModel var viewModel: MyViewModel var body: some View { if #available(iOS 17.0, *) { // Uses Observation on iOS 17+ content } else { // Falls back to ObservableObject on iOS 16 and below content } } ``` -------------------------------- ### Projection Type Usage Example Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/api-reference-swift-property-wrappers.md Illustrates how to use the '$' prefix with a ViewModel property to create a Binding via the Projection. ```swift @StateViewModel var viewModel = FormViewModel() var body: some View { TextField("Name", text: $viewModel.name) // $ creates a Binding through the projection } ``` -------------------------------- ### Automatic Observation Conformance Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/configuration-swift.md Example of adding Observable conformance to a ViewModel for automatic observation support. ```swift extension Kmp_observableviewmodel_coreViewModel: @retroactive Observable { } ``` -------------------------------- ### Form Binding (Swift) Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/quick-reference.md Example of using `@StateViewModel` for form binding in SwiftUI, connecting UI elements to ViewModel properties. ```swift @StateViewModel var formViewModel = FormViewModel() var body: some View { Form { TextField("Name", text: $formViewModel.name) TextField("Email", text: $formViewModel.email) Button("Save") { formViewModel.save() } } } ``` -------------------------------- ### Manage Resources (Kotlin) Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/quick-reference.md Demonstrates how to manage resources like database connections within a ViewModel. ```kotlin class DatabaseViewModel: ViewModel() { init { val db = openDatabase() addCloseable("database", db) } override fun onCleared() { super.onCleared() println("Database closed") } } ``` -------------------------------- ### StateFlow Example Flow Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/architecture-and-design.md Demonstrates how a Kotlin MutableStateFlow is used within a ViewModel and how changes are propagated to the Swift layer for SwiftUI observation. ```kotlin // Kotlin class CounterViewModel: ViewModel() { private val _count = MutableStateFlow(viewModelScope, 0) val count = _count.asStateFlow() fun increment() { _count.value++ // On Apple: emits through publisher } } ``` ```swift // Swift @StateViewModel var viewModel = CounterViewModel() // When increment() is called: // 1. _count.value updated in Kotlin // 2. ObservableMutableStateFlow detects change // 3. Emits through viewModelScope.publisher // 4. ObservableObject publisher notified // 5. SwiftUI view re-renders ``` -------------------------------- ### Complete Example: Kotlin ViewModel Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/api-reference-swift-cancellable.md A simple Kotlin ViewModel emitting data periodically. ```kotlin class DataViewModel: ViewModel() { val dataFlow: Flow = flow { while (isActive) { emit(getData()) delay(1000) } } } ``` -------------------------------- ### Create a Basic ViewModel (Kotlin) Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/quick-reference.md Demonstrates how to create a basic ViewModel in Kotlin with a mutable state flow. ```kotlin import com.rickclephas.kmp.observableviewmodel.ViewModel import com.rickclephas.kmp.observableviewmodel.MutableStateFlow class MyViewModel: ViewModel() { private val _count = MutableStateFlow(viewModelScope, 0) val count = _count.asStateFlow() fun increment() { _count.value++ } } ``` -------------------------------- ### ViewModel with Combine Publisher Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/configuration-swift.md Example of a ViewModel subclassing a Kotlin ViewModel and using Combine for data flow, implementing Cancellable. ```swift import Combine import KMPNativeCoroutinesCombine import shared class MyViewModel: shared.MyKotlinViewModel, Cancellable { private var cancellables = Set() override init() { super.init() createPublisher(for: dataFlow) .sink { value in // Handle value } .store(in: &cancellables) } func cancel() { cancellables = [] } } ``` -------------------------------- ### KMP-NativeCoroutines StateFlow to Swift property Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/README.md Example of using @NativeCoroutinesState to turn a StateFlow into a property in Swift. ```kotlin import com.rickclephas.kmp.nativecoroutines.NativeCoroutinesState import kotlinx.coroutines.flow.StateFlow @NativeCoroutinesState val travelEffect: StateFlow = _travelEffect.asStateFlow() ``` -------------------------------- ### Child ViewModel Setup in Swift Extension Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/configuration-swift.md Swift extension to bridge Kotlin child ViewModel properties, preventing premature deallocation. ```swift // Swift extension import shared extension ParentViewModel { var childViewModel: ChildViewModel? { childViewModel(at: \.__childViewModel) } } ``` -------------------------------- ### Verify Lifecycle (Swift) Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/quick-reference.md Demonstrates how to verify ViewModel creation and deallocation using `didSet` and `deinit`. ```swift @StateViewModel var viewModel: MyViewModel { didSet { print("ViewModel created") } } deinit { print("ViewModel deallocated") } ``` -------------------------------- ### Async Operation with Error Handling (Kotlin) Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/quick-reference.md Example of handling asynchronous operations with loading, success, and error states using Kotlin Coroutines and StateFlow. ```kotlin class FetchViewModel: ViewModel() { private val _state = MutableStateFlow(viewModelScope, State.Idle) val state = _state.asStateFlow() fun fetch() { viewModelScope.launch { _state.value = State.Loading try { val data = fetchFromNetwork() _state.value = State.Success(data) } catch (e: Exception) { _state.value = State.Error(e.message) } } } } ``` -------------------------------- ### Dependency Injection via Environment (Swift) Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/quick-reference.md Demonstrates dependency injection of a ViewModel into child views using the environment. ```swift struct RootView: View { @StateViewModel var viewModel = MyViewModel() var body: some View { ChildView() .environmentViewModel(viewModel) } } struct ChildView: View { @EnvironmentViewModel var viewModel: MyViewModel var body: some View { Text("\(viewModel.count.value)") } } ``` -------------------------------- ### Complete Example: SwiftUI View Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/api-reference-swift-cancellable.md A SwiftUI View using the SwiftDataViewModel, illustrating the cleanup process when the view is destroyed. ```swift struct DataView: View { @StateViewModel var viewModel = SwiftDataViewModel() var body: some View { Text(viewModel.displayText) // When view is destroyed: // 1. cancel() is called // 2. Combine subscriptions are cleared // 3. viewModelScope is cancelled // 4. No JobCancellationException occurs } } ``` -------------------------------- ### Usage Example with Automatic Conformance Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/api-reference-swift-observable.md Views only rerender when accessed properties change when using Observation on iOS 17+. ```swift // With Observation enabled on iOS 17+, views only rerender when accessed properties change @EnvironmentViewModel var viewModel: MyViewModel var body: some View { // Only triggers rerender if viewModel.name actually changes Text(viewModel.name.value) } ``` -------------------------------- ### Observing KMP Flow with Combine Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/README.md Example of using KMPNativeCoroutinesCombine to observe a Kotlin Flow in a Swift ViewModel using Combine. ```swift import Combine import KMPNativeCoroutinesCombine import shared // This should be your shared KMP module class TimeTravelViewModel: shared.TimeTravelViewModel { private var cancellables = Set() override init() { super.init() createPublisher(for: currentTimeFlow) .assertNoFailure() .sink { time in print("It's \(time)") } .store(in: &cancellables) } } ``` -------------------------------- ### Correct MutableStateFlow Constructor Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/api-reference-stateflow.md Example of the correct way to create a MutableStateFlow in a ViewModel, passing the viewModelScope as the first parameter. ```kotlin // Pass viewModelScope as first parameter private val _state = MutableStateFlow(viewModelScope, initialValue) ``` -------------------------------- ### Complete Example: Swift Subclass with Cleanup Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/api-reference-swift-cancellable.md Swift subclass implementing Cancellable to manage Combine subscriptions for a Kotlin ViewModel. ```swift import Combine import KMPNativeCoroutinesCombine import shared class SwiftDataViewModel: shared.DataViewModel, Cancellable { @Published var displayText: String = "" private var cancellables = Set() override init() { super.init() setupPublisher() } private func setupPublisher() { createPublisher(for: dataFlow) .assertNoFailure() .sink { [weak self] text in self?.displayText = text } .store(in: &cancellables) } func cancel() { // Cleanup happens before viewModelScope is cancelled cancellables.forEach { $0.cancel() } cancellables = [] } } ``` -------------------------------- ### Using async/await Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/configuration-kotlin.md Demonstrates using async/await within a ViewModel to fetch data asynchronously. ```kotlin class UserViewModel: ViewModel() { private val _user = MutableStateFlow(viewModelScope, null) val user = _user.asStateFlow() fun loadUser(id: String) { viewModelScope.launch { val userDeferred = viewModelScope.async { fetchUserFromNetwork(id) } _user.value = userDeferred.await() } } } ``` -------------------------------- ### ViewModel Methods Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/quick-reference.md Lists the available methods and properties for the ViewModel class. ```kotlin public val viewModelScope: ViewModelScope public open fun onCleared() public fun addCloseable(key: String, closeable: AutoCloseable) public fun addCloseable(closeable: AutoCloseable) public fun getCloseable(key: String): T? ``` -------------------------------- ### Handle Child ViewModels (Kotlin + Swift) Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/quick-reference.md Shows how to handle child ViewModels in both Kotlin and Swift. ```kotlin // Kotlin @NativeCoroutinesRefinedState val childViewModel: StateFlow = MutableStateFlow(viewModelScope, null) ``` ```swift // Swift extension extension ParentViewModel { var childViewModel: ChildVM? { childViewModel(at: \.__childViewModel) } } ``` -------------------------------- ### Create StateFlow from Flow (Kotlin) Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/quick-reference.md Shows how to create a StateFlow from an existing Flow using the stateIn operator. ```kotlin import com.rickclephas.kmp.observableviewmodel.stateIn import kotlinx.coroutines.flow.SharingStarted class DataViewModel: ViewModel() { val data = fetchData() .stateIn(viewModelScope, SharingStarted.WhileSubscribed(), null) } ``` -------------------------------- ### Use ViewModel in SwiftUI (Swift) Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/quick-reference.md Illustrates how to use a ViewModel in a SwiftUI view using the @StateViewModel property wrapper. ```swift import SwiftUI import KMPObservableViewModelSwiftUI import shared struct ContentView: View { @StateViewModel var viewModel = MyViewModel() var body: some View { VStack { Text("Count: \(viewModel.count.value)") Button("Increment") { viewModel.increment() } } } } ``` -------------------------------- ### StateFlow Functions Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/quick-reference.md Lists the functions for creating and managing StateFlows. ```kotlin public fun MutableStateFlow( viewModelScope: ViewModelScope, value: T ): MutableStateFlow public fun Flow.stateIn( viewModelScope: ViewModelScope, started: SharingStarted, initialValue: T ): StateFlow ``` -------------------------------- ### Multiple Launch Contexts Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/configuration-kotlin.md Shows how to launch coroutines in different dispatchers, like Dispatchers.IO, for background tasks. ```kotlin class AnalyticsViewModel: ViewModel() { fun trackEvent(name: String) { viewModelScope.launch(Dispatchers.IO) { writeToAnalyticsDatabase(name) } } } ``` -------------------------------- ### ViewModel Constructors Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/quick-reference.md Lists the available constructors for the ViewModel class. ```kotlin public ViewModel() public ViewModel(coroutineScope: CoroutineScope) public ViewModel(vararg closeables: AutoCloseable) public ViewModel(coroutineScope: CoroutineScope, vararg closeables: AutoCloseable) ``` -------------------------------- ### Dependency Management: api() vs implementation() Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/configuration-kotlin.md Illustrates the correct way to declare KMP-ObservableViewModel dependencies in Gradle using api() instead of implementation(). ```kotlin // ✓ Correct dependencies { api("com.rickclephas.kmp:kmp-observableviewmodel-core:1.0.4") } // ✗ Wrong dependencies { implementation("com.rickclephas.kmp:kmp-observableviewmodel-core:1.0.4") } ``` -------------------------------- ### Source Set Organization Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/architecture-and-design.md Illustrates the directory structure and file organization within the KMP-ObservableViewModel library, highlighting the different source sets (commonMain, androidxMain, nonAndroidxMain, appleMain, nonAppleMain, nativeInterop) and their respective files. ```text kmp-observableviewmodel-core/src/ ├── commonMain/ │ ├── ViewModel.kt (expect class) │ ├── ViewModelScope.kt (expect interface) │ ├── StateFlow.kt (expect functions) │ ├── ViewModelScopeUtils.kt (extensions) │ ├── DefaultCoroutineScope.kt (internal) │ └── InternalKMPObservableViewModelApi.kt (annotation) │ ├── androidxMain/ │ └── ViewModel.kt (actual - extends androidx.lifecycle.ViewModel) │ ├── nonAndroidxMain/ │ ├── ViewModel.kt (actual - basic implementation) │ └── Closeables.kt (resource management) │ ├── appleMain/ │ ├── ViewModel.kt (actual - NSObject) │ ├── ViewModelScope.kt (actual - NativeViewModelScope) │ ├── StateFlow.kt (actual - ObservableMutableStateFlow) │ ├── NativeViewModelScope.kt (iOS integration) │ ├── ObservableStateFlow.kt (SwiftUI wrapper) │ ├── SubscriptionCount.kt (SwiftUI tracking) │ └── CombinedSubscriptionCount.kt │ ├── nonAppleMain/ │ ├── ViewModelScope.kt (actual - ViewModelScopeImpl) │ └── StateFlow.kt (actual - delegates to stdlib) │ └── nativeInterop/ └── KMP-ObservableViewModel headers ``` -------------------------------- ### Reading State Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/api-reference-stateflow.md Gets the current value without collecting. Safe to call from any context. ```kotlin val currentValue = stateFlow.value ``` -------------------------------- ### coroutineScope Property Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/api-reference-viewmodelscope.md Gets the CoroutineScope associated with this ViewModelScope. The scope is cancelled when the ViewModel is destroyed. ```kotlin public expect val ViewModelScope.coroutineScope: CoroutineScope ``` -------------------------------- ### Swift Extensions Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/quick-reference.md Lists the available Swift extension functions for ViewModel and View. ```swift public extension ViewModel { var childViewModel(at: KeyPath) -> VM? func childViewModels(at: KeyPath) -> [VM]? func childViewModels(at: KeyPath) -> Set? func childViewModels(at: KeyPath) -> [Key: VM]? } public extension View { func environmentViewModel(_ viewModel: VM) -> some View } ``` -------------------------------- ### watchOS Support Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/configuration-swift.md Notes on watchOS support and property wrapper usage for watchOS 7+. ```swift @available(watchOS 7.0, *) // Use property wrappers for watchOS 7+ ``` -------------------------------- ### Incorrect MutableStateFlow Constructor Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/api-reference-stateflow.md Example of an incorrect way to create a MutableStateFlow in a ViewModel, missing the viewModelScope parameter. ```kotlin // Don't do this - missing viewModelScope parameter private val _state = MutableStateFlow(initialValue) ``` -------------------------------- ### EnvironmentViewModel Initialization Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/api-reference-swift-property-wrappers.md Shows the initializer for @EnvironmentViewModel, which takes no parameters as the ViewModel is provided by the environment. ```swift public init() ``` -------------------------------- ### Basic Pattern - Kotlin and Swift Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/api-reference-swift-child-viewmodels.md Illustrates the basic pattern for using childViewModel() with Kotlin StateFlows and Swift extensions. ```kotlin // In Kotlin @NativeCoroutinesRefinedState val childViewModel: StateFlow = MutableStateFlow(viewModelScope, null) ``` ```swift // In Swift - create extension property extension ParentViewModel { var childViewModel: ChildViewModel? { // Call childViewModel(at:) with keyPath to Kotlin property childViewModel(at: \.__childViewModel) } } ``` -------------------------------- ### Retrieving Resources Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/configuration-kotlin.md Shows how to retrieve previously added closeable resources using getCloseable. ```kotlin class MultiResourceViewModel: ViewModel() { init { val db = openDatabase() val file = openFile() addCloseable("database", db) addCloseable("file", file) } fun closeDatabase() { val db: Database? = getCloseable("database") if (db != null) { // Use or manage the database } } } ``` -------------------------------- ### ObservedViewModel Usage Example Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/api-reference-swift-property-wrappers.md ObservedViewModel is passed the ViewModel from the parent view. The child observes changes to the ViewModel but doesn't own its lifecycle. ```swift import SwiftUI import KMPObservableViewModelSwiftUI import shared struct ChildView: View { @ObservedViewModel var viewModel: TimeTravelViewModel var body: some View { VStack { Text("Travel Effect: \(viewModel.travelEffect.value ?? \"None\")") } } } struct ParentView: View { @StateViewModel var parentViewModel = ParentViewModel() var body: some View { ChildView(viewModel: parentViewModel.childViewModel) } } ``` -------------------------------- ### Adding Resources via addCloseable Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/configuration-kotlin.md Demonstrates using addCloseable to manage resources created after the ViewModel's initialization. ```kotlin class DataViewModel: ViewModel() { init { val db = openDatabase() addCloseable("database", db) } override fun onCleared() { super.onCleared() println("Database has been closed") } } ``` -------------------------------- ### Important Imports (Kotlin) Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/quick-reference.md Lists the essential imports for using KMP-ObservableViewModel in Kotlin. ```kotlin import com.rickclephas.kmp.observableviewmodel.ViewModel import com.rickclephas.kmp.observableviewmodel.ViewModelScope import com.rickclephas.kmp.observableviewmodel.MutableStateFlow import com.rickclephas.kmp.observableviewmodel.stateIn ``` -------------------------------- ### tvOS Support Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/configuration-swift.md Indicates tvOS support and the use of standard property wrappers. ```swift @available(tvOS 14.0, *) // Use all standard property wrappers ``` -------------------------------- ### Problem: Combine Publisher Outliving ViewModel Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/api-reference-swift-cancellable.md Example demonstrating a Combine sink potentially outliving the underlying StateFlow collection when subclassing a Kotlin ViewModel in Swift. ```swift import Combine import KMPNativeCoroutinesCombine import shared class TimeTravelViewModel: shared.TimeTravelViewModel { private var cancellables = Set() override init() { super.init() createPublisher(for: currentTimeFlow) .assertNoFailure() .sink { time in print("It's \(time)") } .store(in: &cancellables) } } ``` -------------------------------- ### Required Imports for All Projects Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/configuration-swift.md Imports needed for all projects using the library. ```swift import KMPObservableViewModelCore import shared // Your Kotlin shared module ``` -------------------------------- ### ViewModelScope Extensions Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/quick-reference.md Lists the available extension functions for ViewModelScope. ```kotlin public inline val ViewModelScope.isActive: Boolean public inline fun ViewModelScope.launch(...): Job public inline fun ViewModelScope.async(...): Deferred public inline fun ViewModelScope.ensureActive(): Unit public inline fun ViewModelScope.produce(...): ReceiveChannel ``` -------------------------------- ### Adding Resources via Constructor Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/configuration-kotlin.md Illustrates adding resources that are automatically closed when the ViewModel is cleared, when passed via the constructor. ```kotlin class FileViewModel(file: File): ViewModel(file) { val content = file.readText() override fun onCleared() { super.onCleared() println("File will be closed now") } } ``` -------------------------------- ### Using KMP-NativeCoroutines Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/api-reference-swift-cancellable.md Demonstrates how to integrate KMP-NativeCoroutines with KMP-ObservableViewModel by converting Kotlin Flows to Combine publishers and managing their subscriptions. ```swift import KMPNativeCoroutinesCombine import shared class MyViewModel: shared.MyKotlinViewModel, Cancellable { private var cancellables = Set() override init() { super.init() // Create publisher from Kotlin Flow createPublisher(for: myKotlinFlow) .sink { // Handle value } .store(in: &cancellables) } func cancel() { cancellables = [] } } ``` -------------------------------- ### Required Imports for SwiftUI Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/configuration-swift.md Additional imports required when using SwiftUI. ```swift import SwiftUI import KMPObservableViewModelSwiftUI import KMPObservableViewModelCore import shared ``` -------------------------------- ### @ObservedViewModel Initialization Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/api-reference-swift-property-wrappers.md The initializer for @ObservedViewModel, which takes an existing ViewModel instance to observe. ```swift public init(wrappedValue: VM) ``` -------------------------------- ### Integration with KMP-NativeCoroutines Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/configuration-kotlin.md Demonstrates integrating KMP-ObservableViewModel with KMP-NativeCoroutines, specifically using @NativeCoroutinesState for StateFlows. ```kotlin import com.rickclephas.kmp.observableviewmodel.MutableStateFlow import io.github.rickclephas.kmp.nativecoroutines.NativeCoroutinesState class TimeTravelViewModel: ViewModel() { private val _travelEffect = MutableStateFlow(viewModelScope, null) @NativeCoroutinesState val travelEffect = _travelEffect.asStateFlow() } ``` -------------------------------- ### Package.swift Configuration Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/configuration-swift.md Add the KMP-ObservableViewModel packages to your Swift Package Manager dependencies. ```swift dependencies: [ .package(url: "https://github.com/rickclephas/KMP-ObservableViewModel.git", from: "1.0.4") ] ``` -------------------------------- ### Dynamic Member Lookup for Bindings Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/architecture-and-design.md Demonstrates how the `Projection` type, using dynamic member lookup, enables the creation of SwiftUI `Binding` objects for ViewModel properties. ```swift @StateViewModel var viewModel: FormViewModel // $viewModel.name accesses: struct Projection { subscript(dynamicMember keyPath: WritableKeyPath) -> Binding } // Creates: Binding { viewModel.name } set: { viewModel.name = $0 } ``` -------------------------------- ### Correct @retroactive Usage Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/configuration-swift.md Demonstrates the correct usage of the @retroactive keyword for ViewModel conformance. ```swift // ✓ Correct - allows conformance to be added extension Kmp_observableviewmodel_coreViewModel: @retroactive ViewModel { } // ✗ Wrong - may cause issues extension Kmp_observableviewmodel_coreViewModel: ViewModel { } ``` -------------------------------- ### Basic ViewModel Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/configuration-kotlin.md Extends ViewModel to create a multiplatform ViewModel. The no-argument constructor creates a default CoroutineScope. ```kotlin import com.rickclephas.kmp.observableviewmodel.ViewModel open class MyViewModel: ViewModel() { // ViewModel code } ``` -------------------------------- ### Resource Scoping Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/configuration-kotlin.md Demonstrates proper resource scoping within a ViewModel using addCloseable to tie resources to the ViewModel's lifecycle. ```kotlin // ✓ Correct - resources tied to ViewModel lifecycle class ViewModel: ViewModel() { private val resource = acquireResource() init { addCloseable(resource) } } // ✗ Wrong - resources may leak if ViewModel is destroyed class ViewModel: ViewModel() { private var resource: Resource? = null fun startWork() { resource = acquireResource() } } ``` -------------------------------- ### Publisher Protocol Chain Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/architecture-and-design.md Illustrates the chain of communication from a Kotlin ViewModel to a SwiftUI View Update, involving native scopes, publishers, and Combine. ```kotlin // Kotlin ViewModel ↓ NativeViewModelScope ├─→ coroutineScope: CoroutineScope ├─→ subscriptionCount: SubscriptionCount (tracks SwiftUI subscribers) └─→ publisher: KMPOVMPublisherProtocol? ↓ Swift ObservableViewModelPublisher ├─→ Inherits from Combine.Publisher ├─→ Implements KMPOVMPublisher protocol ├─→ Tracks property access (iOS 17+) └─→ Emits ObjectWillChange for SwiftUI ↓ SwiftUI View Update ``` -------------------------------- ### Swift Imports Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/quick-reference.md Imports for using KMP Observable ViewModel in Swift projects, including Observation for iOS 17+. ```swift import KMPObservableViewModelCore import KMPObservableViewModelSwiftUI import Observation // iOS 17+ only ``` -------------------------------- ### @StateViewModel Initialization Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/api-reference-swift-property-wrappers.md The initializer for @StateViewModel, which accepts a closure to create the ViewModel instance. ```swift public init(wrappedValue: @autoclosure @escaping () -> VM) ``` -------------------------------- ### Observable Support (iOS 17+) Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/quick-reference.md Extending KMP ViewModel to conform to the `Observable` protocol for SwiftUI integration on iOS 17+. ```swift import Observation extension Kmp_observableviewmodel_coreViewModel: @retroactive Observable { } // Views only re-render if accessed property changes @EnvironmentViewModel var viewModel: MyViewModel var body: some View { Text(viewModel.property1.value) // Re-renders only when property1 changes } ``` -------------------------------- ### Multi-Layer Design Diagram Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/architecture-and-design.md A visual representation of the KMP-ObservableViewModel's layered architecture, showing the UI layer, platform-specific layers, the common Kotlin Multiplatform layer, and the underlying coroutines/standard library. ```text ┌─────────────────────────────────────────────────┐ │ SwiftUI/Android UI Layer │ │ (ObservableObject, @StateViewModel, etc.) │ └─────────────────────────────────────────────────┘ ↑ ↑ ↑ │ │ │ ┌─────────────┴──────┬────┴───┬──────┴──────────┐ │ iOS/macOS │ Android │ Other Targets │ │ (NativeViewModelScope, │ (ViewModelScopeImpl) │ SwiftUI integration) (AndroidXViewModel) └────────────────────┴────────┴─────────────────┘ ↑ ↑ ↑ │ │ │ ┌─────────────┴───────────┴───────────┴──────────┐ │ Common Kotlin Multiplatform Layer │ │ (expect/actual ViewModel, ViewModelScope) │ └──────────────────────────────────────────────┘ ↑ │ ┌─────────────┴──────────────────────────────────┐ │ Kotlin Coroutines & Standard Library │ └─────────────────────────────────────────────────┘ ``` -------------------------------- ### Implementing Cancellable Protocol Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/README.md Solution to prevent Combine publisher issues by conforming to the Cancellable protocol and implementing the cancel function. ```swift class TimeTravelViewModel: shared.TimeTravelViewModel, Cancellable { func cancel() { cancellables = [] } } ``` -------------------------------- ### Subscription Count Tracking Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/architecture-and-design.md Shows how the library tracks active SwiftUI subscribers to manage coroutine collection, combining subscriber counts from both SwiftUI and Kotlin Flows. ```kotlin // In ObservableMutableStateFlow override val subscriptionCount: StateFlow = CombinedSubscriptionCount(viewModelScope, stateFlow) // Combines: // 1. SwiftUI subscriber count (from publisher) // 2. Kotlin Flow subscriber count (from StateFlow) ``` -------------------------------- ### Launching Coroutines Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/configuration-kotlin.md Launches coroutines using viewModelScope.launch for asynchronous operations, ensuring automatic cancellation when the ViewModel is cleared. ```kotlin import com.rickclephas.kmp.observableviewmodel.MutableStateFlow class FetchViewModel: ViewModel() { private val _items = MutableStateFlow(viewModelScope, emptyList()) val items = _items.asStateFlow() fun loadItems() { viewModelScope.launch { try { val fetchedItems = fetchFromNetwork() _items.value = fetchedItems } catch (e: Exception) { // Handle error } } } } ``` -------------------------------- ### MutableStateFlow Constructor Difference Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/README.md A diff illustrating the difference in the MutableStateFlow constructor, showing the addition of viewModelScope. ```diff - import kotlinx.coroutines.flow.MutableStateFlow + import com.rickclephas.kmp.observableviewmodel.MutableStateFlow - private val _travelEffect = MutableStateFlow(null) + private val _travelEffect = MutableStateFlow(viewModelScope, null) ``` -------------------------------- ### SwiftUI Property Wrapper Integration Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/architecture-and-design.md Explains how the `@StateViewModel` property wrapper integrates with SwiftUI, creating and managing an `ObservableViewModel` wrapper for a ViewModel. ```swift User code ↓ @StateViewModel var vm: MyViewModel ├─→ Creates StateObject> ├─→ Wraps MyViewModel └─→ observableViewModel(for:) factory function ↓ ObservableViewModel wrapper ├─→ Stores strong reference to ViewModel ├─→ Exposes viewModel property ├─→ Provides objectWillChange publisher └─→ Manages lifecycle ↓ Swift layer can now observe changes ``` -------------------------------- ### Default Constructor Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/api-reference-viewmodel.md Creates a ViewModel with a default CoroutineScope using the Main dispatcher if available. ```kotlin public expect abstract class ViewModel { public constructor() } ``` -------------------------------- ### Cancellable Implementation Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/configuration-swift.md Correct and incorrect implementations of the Cancellable protocol for ViewModels. ```swift // ✓ Correct - cleanup is explicit class MyViewModel: shared.MyViewModel, Cancellable { private var cancellables = Set() func cancel() { cancellables = [] } } // ✗ Wrong - may cause JobCancellationException class MyViewModel: shared.MyViewModel { private var cancellables = Set() // Missing cancel() implementation } ``` -------------------------------- ### Gradle Dependency Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/configuration-kotlin.md Adds the KMP-ObservableViewModel library to the shared Kotlin module's build.gradle.kts file. ```kotlin kotlin { sourceSets { all { languageSettings.optIn("kotlinx.cinterop.ExperimentalForeignApi") } commonMain { dependencies { api("com.rickclephas.kmp:kmp-observableviewmodel-core:1.0.4") } } } } ``` -------------------------------- ### Required Imports for Observable Support (iOS 17+) Source: https://github.com/rickclephas/kmp-observableviewmodel/blob/master/_autodocs/configuration-swift.md Imports for projects using the native Observation framework on iOS 17+. ```swift import Observation // iOS 17.0+, macOS 14.0+, tvOS 17.0+, watchOS 10.0+ import KMPObservableViewModelCore import shared ```