rickclephas / KMP-ObservableViewModel

Library to use AndroidX/Kotlin ViewModels with SwiftUI
MIT License
570 stars 28 forks source link

ViewModel constructor parameters on iOS #22

Closed aurimas-zarskis closed 1 year ago

aurimas-zarskis commented 1 year ago

Hey, on android side Koin DI allows passing constructor parameters to VM like item id etc. But on iOS, this is not possible. If I try to initialize ViewModel inside init block of my View, it doesn't compile saying get-only value can't be assigned. I'm not very familiar with swift and might be doing something wrong, if thats the case some guidance would be appreciated

rickclephas commented 1 year ago

Hi! I am not that familiar with Koin DI. Could you possibly share some code snippets that demonstrate the usage in Android and the issue in iOS?

aurimas-zarskis commented 1 year ago

Thanks for quick reply, here is some code:

struct TestView: View {
    @ObservedViewModel var viewModel: TestViewModel

    init(id: String) {
        viewModel = TestViewModel(userId: id) // Error is here
    }

    var body: some View {
        ZStack {
            //.... UI code
        }
    }
}

class TestViewModel(private val userId: String): KMMViewModel() {
    // VM code
}

This produces error: Cannot assign to property: 'viewModel' is a get-only property I don't think this issues is related to Koin in any way, it's just that @ObservedViewModel prevents ViewModel from being initialized in init block of view, where parameters are available. Removing @ObservedViewModel allows ViewModel to be initialized, but this produces errors where I'm observing flows.

aurimas-zarskis commented 1 year ago

I think I found solution to my own problem 😆 I took a look at #18 and saw that there is another way to initialize ViewModel:

struct TestView: View {
    @ObservedViewModel var viewModel: TestViewModel

    init(id: String) {
        self._viewModel = ObservedViewModel(wrappedValue: TestViewModel(userId: id))
    }

    var body: some View {
        ZStack {
            //.... UI code
        }
    }
}

This seems to work just like I needed. I think it would be worth adding such example in the docs as I think this would be helpful for some people.

rickclephas commented 1 year ago

Awesome that would indeed be the way to initialise the ViewModel within the init. Will take a look at the docs 😄.

rickclephas commented 1 year ago

v1.0.0-ALPHA-7 adds setter support for @ObservedViewModel properties, meaning the following is now supported:

@ObservedViewModel var viewModel: TestViewModel

init(id: String) {
    viewModel = TestViewModel(userId: id)
}
kansson commented 1 month ago

@rickclephas can setter support also be added for @StateViewModel?

rickclephas commented 1 month ago

@kansson @StateViewModel uses @StateObject which doesn't have a setter for the wrappedValue. @StateObject automatically creates the object using the closure provided in the constructor.