timkranen
06/30/2022, 3:38 PMviewModel
scope. But I’m running into problems on iOS with regards to the lifecycle.. Currently my VM is marked as a singleton for iOS, however there are a couple of problems that arise:
• Initially I thought it would be a good idea to cancel the scope in the viewModel on viewDisappeared, but when I’m navigating back to that same screen Koin will provide the same VM with a cancelled coroutine scope, so that breaks stuff..
• Changing the viewModel to be a factory solves this problem, but then I can’t retain state across screen navigation, which isn’t the end of the world and I can make it work, but it seems like it’s limiting? It also introduces the problem of somehow having to manually save state like scroll positions
What are your approaches to the lifecycle of viewmodels on iOS? When do you cancel the scope? Does the VM retain state across navigation?clark
07/01/2022, 4:37 PMMatti MK
07/04/2022, 5:32 AMKaMPKit
sample:
https://github.com/touchlab/KaMPKit/blob/main/shared/src/iosMain/kotlin/co/touchlab/kampkit/models/ViewModel.kttimkranen
07/04/2022, 8:08 AM.onDisappeared
aren’t called when navigating to detail screens on iOS. So what we can do is:
• Initialize a new viewmodel on every .onAppear
, can keep this viewmodel in memory through an ObservableObject
. Whenever we navigate to a detail view, the VM is retained, so coming back to the original screen leaves the original state. But when navigating away from the screen entirely .onDisappeared
is called, the VM is cleaned up, and once .onAppear
gets called again a new instance of the VM is created.
• We use Koru to map kotlin Flow to swift combine, this basically allows us to keep all the view state logic inside the VM except for: observing state changes (through combine).single
for the iOS VM. I wonder how they deal with VM instances that have a cancelled scope in the ViewModel..Matti MK
07/04/2022, 9:00 AMSwiftUI
-> ViewModelWrapper
-> KMMSharedViewModel
-> UC
-> data layer
Here the VM wrapper does what you mentioned: observing state changes (through combine)
timkranen
07/04/2022, 9:04 AMMatti MK
07/04/2022, 9:08 AMshowError
and showLoading
etc on VMs.
KMM VM sharing does work very nicely towards Android, though.@Published
properties cannot be mocked/doubled for tests. This means that you’ll end up with a form of an integration test. I don’t remember why it didn’t seem feasible to mock out the KMM VM in the iOS VM wrapper, but there was an issue.
When I mention mocking here, it’s not the same as mocking on Android as iOS doesn’t have reflection. “Mocks” need to be generated beforehand and IIRC the mocking tools (Cuckoo
for example) wasn’t able to access the KMM cocoapods dep.
But my memory on this is a bit vague so it might be that this is not the case really. And might be that it’s the same issue if iOS just consumes UC directly: at least the @Published
wrapper issue doesn’t change.UIViewController
based navigation with SwiftUI views.
In case you haven’t tested the above, then I’d start there. If all native iOS components don’t keep state, then you might be doing something incorrect in your iOS navigation.