Haydn Morris
Haydn Morris

Reputation: 83

Using Kotlin mulitplatform classes in SwiftUI

I am building a small project using the Kotlin Mulitplatform Mobile (KMM) framework and am using SwiftUI for the iOS application part of the project (both of which I have never used before).

In the boilerplate for the KMM application there is a Greeting class which has a greeting method that returns a string:

package com.example.myfirstapp.shared

class Greeting {
    fun greeting(): String {
        return "Hello World!"
    }
}

If the shared package is imported into the iOS project using SwiftUI, then the greeting method can be invoked and the string that's returned can put into the View (e.g. Text(Greeting().greeting()))

I have implemented a different shared Kotlin class whose properties are modified/fetched using getters and setters, e.g. for simplicity:

package com.example.myfirstapp.shared

class Counter {
    private var count: Int = 0

    getCount() {
        return count
    }

    increment() {
        count++
    }
}

In my Android app I can just instantiate the class and call the setters to mutate the properties of the class and use it as application state. However, I have tried a number of different ways but cannot seem to find the correct way to do this within SwiftUI.

I am able to create the class by either creating a piece of state within the View that I want to use the Counter class in:

@State counter: Counter = shared.Counter()

If I do this then using the getCount() method I can see the initial count property of the class (0), but I am not able to use the setter increment() to modify the property the same way that I can in the Android Activity.

Any advice on the correct/best way to do this would be greatly appreciated!

Here's an example of what I'd like to be able to do just in case that helps:

import shared
import SwiftUI

struct CounterView: View {
    @State var counter: shared.Counter = shared.Counter() // Maybe should be @StateObject?

    
    var body: some View {
        VStack {
            Text("Count: \(counter.getCount())")
            Button("Increment") {    // Pressing this button updates the
                counter.increment()  // UI state on the previous line
            }
        }
    }
}

Upvotes: 1

Views: 1805

Answers (1)

John O'Reilly
John O'Reilly

Reputation: 10330

I believe the fundamental issue is that there isn't anything that's notifying SwiftUI layer when the count property is changed in the shared code (when increment is called). You can at least verify that value is being incremented by doing something like following (where we manually retrieve updated count after incrementing it)



struct ContentView: View {
    @ObservedObject var viewModel = ViewModel(counter: Counter())
    
    var body: some View {
        VStack {
            Text("Count: \(viewModel.count)")
            Button("Increment") {
                viewModel.increment() 
            }
        }
    }
}


class ViewModel: ObservableObject {
    @Published var count: Int32 = 0

    func increment() {
        counter.increment()
        count = counter.getCount()
    }
    
    private let counter: Counter
    init(counter: Counter) {
        self.counter = counter
    }
}

Upvotes: 5

Related Questions