https://kotlinlang.org logo
#ios
Title
# ios
c

Christopher Mederos

11/18/2023, 5:22 AM
I'm working on a KMP project and have all my api & cache logic written in shared code, and am writing in swiftUI and compose for the respective UIs. I'm looking for a good example of swift architecture if anyone can share an example! Something showing a text field that is edited, sends a request to a server when 'saved', and shows the loading/error states along the way as necessary.
Surprisingly, the docs around EditButton, Form, TextField, etc. really don't have any explanation of how they work in an async maner
Seems like a lot is driven off of .onDissapear(). However, I'd like to show a loading icon and any errors on the "editing" view screen itself
essentially the swift version of this
s

Sam

11/20/2023, 3:22 PM
The standard SwiftUI button doesn't work with asynchronous callbacks. One trick is to implement your own
AsyncButton
. It's rather simple to do.
Copy code
public struct AsyncButton<Label: View>: View {
    let action: () async -> Void
    @ViewBuilder var label: () -> Label

    @State var inProgress: Bool = false

    public init(action: @escaping () async -> Void, label: @escaping () -> Label) {
        self.action = action
        self.label = label
    }

    public var body: some View {
        Button(
            action: {
                inProgress = true
                Task {
                    await action()
                    await MainActor.run {
                        inProgress = false
                    }
                }
            },
            label: label)
        .disabled(inProgress)
    }
}
You can then apply whatever modifiers to it that you want and the
Button
struct will pick them up.
Copy code
struct SkipButton: View {
    let action: () async -> Void
    var body: some View {
        AsyncButton(action: action, label: {
            Text("Skip this step")
        }).buttonStyle(.textButton)
    }
}
Another thing people do is apply the
disabled
view modifier at an appropriately high enough level in your hierarchy to disable buttons and form fields while a form is processing.
Copy code
VStack {
  // Children Views
}.disabled(viewModel.processing))
Due to the way SwiftUI works this cascades down view modifiers anything in that VStack can disable itself.
💯 1
c

Christopher Mederos

11/21/2023, 3:00 AM
@Sam that's extremely helpful - thanks for commenting! The .disabled trick answers my next question as well