in my viewModel I have ```val mileageLog: StateFlo...
# multiplatform
k
in my viewModel I have
Copy code
val mileageLog: StateFlow<List<MileageLogEntry>?> = _mileageLog.asStateFlow()
and in swiftUI I’m trying to display all of the items,
Copy code
List {
  ForEach(viewModel.mileageLog!, id: \.self) { entry in
     MileageLogListItem(viewModel: viewModel, entry: entry, showEntryEditor: $showEntryEditor)
  }
}
but when I emit a new list I get
[SwiftUI] Publishing changes from background threads is not allowed; make sure to publish values from the main thread (via operators like receive(on:)) on model updates.
. What’s the appropriate way to get the List to refresh in swift code?
r
What does your Kotlin code that updates the
mileageLog
look like? Also what logic are you using to propagate the state changes to Swift?
k
Copy code
_mileageLog.emit(/* new list */)
and I’m using rickclephas’ KMM-ViewModel library with a viewmodel in kotlin and it being referenced in swift with
@StateViewModel *var* mileageLogViewModel: MileageLogViewModel = InjectApplicationComponent().mileageLogViewModel
r
Hmm alright. In that case I would expect the
emit
call not to be on the main thread. But that doesn't seem to be the case. Are you sure the error message is about the
mileageLog
?
k
pretty sure. Still experimenting with some possible fixes now. Also, I just realized that you are Rick. Thank you for creating some very useful libraries
😁 1
r
🙂. If the error persists please open an issue with a reproduction sample and I will take a look at it 👍🏻
k
ok, figured out the first part of the issue. I got the “publishing changes from background threads is not allowed” problem to go away by wrapping the emit call in
Copy code
viewModelScope.coroutineScope.launch
The list still isn’t updating though so still have to figure that out
r
Ah I missed that one. In that case since it’s already in a suspend function could just wrap it in a
withContext(Dispatchers.Main) {}
call. Which will make sure to run the emit on the main thread, while still waiting for the emit call to complete before returning from
deleteMileageLogEntry
. On the Swift side just make sure to use one of the
@XViewModel
property wrappers (e.g.
@ObservedViewModel
) on the
viewModel
property. That should be enough to propagate the changes to SwiftUI.
k
adding @StateViewModel back to the viewmodel fixed that. I was trying @Binding, then read something that said don’t do that, but didn’t think about adding the other annotation back. The important thing, it works! Thank you for the info
👍🏻 1
r
I had the same message. I’ve solved it with an
@ObservedViewModel
that I forgot to apply
Copy code
class HomeModel: ObservableObject {
    // Fix log spam: Publishing changes from background threads is not allowed; make sure to publish values from the main thread.
    // Ensure the changes are done in the Main thread
    @ObservedViewModel
    private var viewModel = HomeComponent().homeViewModel

    ...
}
Solved thanks to this thread 😂🫶