https://kotlinlang.org logo
#touchlab-tools
Title
# touchlab-tools
a

Andrew Reed

09/27/2023, 12:46 PM
A quick (spoiler, its not quick) question on SkieSwiftFlow, at the moment there is no nice way to get a flow to play nicely with SwiftUI? like you get out of the box with Compose. For example in compose, i would usually do something like:
Copy code
@Compose
fun coolView(viewModel: CoolViewModel) {
val coolValue = viewModel.fooFlow.collectAsState()
....
Whereas in swift, really i would like to be able to do something like this:
Copy code
struct CoolView: View {
let viewModel: CoolViewModel
@State var coolValue = viewModel.fooFlow.collectAsState()
....
I was just wondering if anybody came up with a smart extension for this?
Copy code
extension SkieSwiftFlow {
    func collectValue(callback: @escaping (_ value: T) -> Void) {
        Task.init {
           for await awaitedValue in self {
               callback(awaitedValue)
           }
        }
    }
}
Then you could. do something like:
Copy code
struct CoolView: View {
let viewModel: CoolViewModel
@State var coolValue: Bool = false
init (viewModel: CoolViewModel) {
   self.viewModel = viewModel
   viewModel.fooFlow.collectValue {
      self.coolValue = $0
   }
}
....
Sorry for the essay, but how else do people collect values from the SKIE flow? i saw the mainActor stuff, but it would be noisy for lots of values, unless you created your own wrapper viewmodel and did it there but im a beleiver that the Kotlin generated view model should be useable from native without a wrapper.
s

streetsofboston

09/27/2023, 1:14 PM
IUCC, For SwiftUI you still would need an
Observable
class (like a ViewModel) that holds
Published
vars describing your UI-state. A wrapper would be needed, regardless. It'd be nice if Skie could make such a wrapper as well (backed by a KMP ViewModel class) 😁 Right now, I'm using async for-loops in Swift for collecting the Skie Flows.
a

Andrew Reed

09/27/2023, 2:48 PM
yeah exactly
im not a fan of the async for loops, as there is alot of boilerplate, seems messy when you have lots of flows
💯 1
s

streetsofboston

09/27/2023, 3:02 PM
Yup, if you have more than one Skie Flow, using a for loop and want to preserve the structured concurrency, you'll need to deal with Task-groups in swift.... No easy
launchIn
or some sort of method...
a

Andrew Reed

09/27/2023, 5:05 PM
yeah
r

russhwolf

09/27/2023, 5:06 PM
SKIE is still new. I could see a future where we add more codegen for this, but I don't think we know exactly what it would look like yet. I'm usually using
for async
loops, though the project I'm currently focused on isn't sharing viewmodels so this all happens a little lower down. Beyond SKIE, I think there's a gap even in the pure Swift ecosystem around making it easier to bind the output of an AsyncSequence to SwiftUI, but I also haven't caught up with the latest versions of Swift/SwiftUI to know what's been added around this.
If you have patterns you like that would be helpful to have generated, that's probably useful input for us
a

Andrew Reed

09/27/2023, 5:07 PM
so in most of my KMP projects, i do all the multiplatform stuff up to the view models, the UI i handle natively and drive the views with the KMP view models
SwiftUI and Compose lean towards mvvm so i would prefer support for this
where my vm comes from KMP and i want to make my native views be able to consume the view models easily. The api for android is easy, swiftui unfortunately not yet
r

russhwolf

09/27/2023, 5:10 PM
A KaMPKit update is also in the works which has a version of this, but it's still a little verbose at the moment. It does things in a
task
modifier on the swiftui view. You could pull that out into an extension but the generics can get a bit messy when you need it to interact with an arbitrary viewmodel
I understand the overall use-case. I think the details of what it looks like are less clear. Once we've had more time to use all this stuff in different scenarios and get feedback, it will be easier to see what new functionality might make sense in SKIE
a

Andrew Reed

09/27/2023, 5:19 PM
in an ideal world, i would foresee, an KMP viewmodel object type, for Android this would use the ViewModel type that has all the lifecycles attached to it. For iOS i guess would be an observableobject
and then for android for flows, it would be collectAsStateFlow, for iOS i guess would expose as a publisher
ah i see it in the docs for general architecture of kampkit
r

russhwolf

09/27/2023, 5:29 PM
Those docs are pre-SKIE still. General idea stays the same but the details look a little different.
k

kpgalligan

09/27/2023, 8:09 PM
I sort of skipped from the top as I'm having one of "those" days where I'm super busy, but the
collectAsState()
and something similar for SwiftUI on top of SKIE (or separate, depending) is big on my mind now. One of the primary SKIE devs built this https://github.com/Brightify/Hyperdrive, which (in part) does this kind of thing, but using Objc classes. My thinking is really just that StateFlow could be exposed as form form of "state", and consumed that way, rather than the loop. That might be enough, but my SwiftUI architectural understanding is a bit underdeveloped to think through the range of scenarios that would need to be addressed, and how whatever is accessing that state is created, it's lifecycle, etc. I really don't want to prescribe extra ceremony around any sort of lifecycle that would be odd from a Swift perspective, though. anyway, we can generate Swift now, and link it back into the framework. Knowing that, what do you think this should look like?
a

Andrew Reed

09/28/2023, 10:10 AM
nice will take a look today
that looks like what i am after
j

Jeff Lockhart

09/28/2023, 3:09 PM
in an ideal world, i would foresee, an KMP viewmodel object type, for Android this would use the ViewModel type that has all the lifecycles attached to it.
For iOS i guess would be an observableobject
Sounds like what @Rick Clephas's https://github.com/rickclephas/KMM-ViewModel does.
👌 1
k

kpgalligan

09/28/2023, 4:35 PM
That is what Rick's library is doing. We've been doing the split at the ViewModel as well, although not with the
StateFlow
to published state in SwiftUI. However, There's a long-standing debate about getting away from
ViewModel
. I'm not 100% set on doing that, but I do think there's some value in thinking through where the shared code split exists, and how that gets exposed on either side. I guess my gut feeling is if you're going to create some kind of "view model", you could have both platforms derive from the same object. Or, you could have something different for iOS that is unrelated. You aren't required to derive from the same base and have a somewhat shared lifecycle. As for generating something on the Swift side, I'm more interested in seeing complex examples of how you'd architect the data if there wasn't any Kotlin in the mix. How are you managing async contexts and lifecycles, etc. We started with various flavors of shared
ViewModel
, capital 'V', and trying to match the lifecycle of the VM with whatever was happening on Swift, but it very much feels like we're pushing an Android abstraction onto SwiftUI. Worse, it's an abstraction that is very much up for debate, even on Android. Yada yada. I want to understand how this would ideally look from Swift if there was no Android-isms in the mix, then work back from there. But, the dog got me up at 5am because he doesn't care about my feelings, and I just did a live stream, so now is probably not the best time to debate architecture :)
😄 1
🤣 1
12 Views