Home > Back-end >  SwiftUI - Passing values to enum
SwiftUI - Passing values to enum

Time:07-13

I am creating some reusable views, but to keep the question and example short, I am sharing limited code for now. Let's say I have created a CustomActionsView which displays the different messages and buttons in various styles as needed.

I created a view builder which returns the view based on different inputs. Sharing code below:

import SwiftUI

struct Destinations {
    var messageText: String = ""
    var viewStyle: Int = 0
    @Binding var showingModal:Bool

    enum CustomDestinations: Int, CaseIterable, Hashable {
        case view1 = 0, view2 = 1, view3 = 2

        @ViewBuilder var view: some View {
            switch self {
            case .view1: CustomActionsView(mainMessageText: self.messageText, viewStyle: 0, showingModal: self.$showingModal)
            case .view2: CustomActionsView(mainMessageText: self.messageText, viewStyle: 1, showingModal: self.$showingModal)
            case .view3: CustomActionsView(mainMessageText: self.messageText, viewStyle: 2, showingModal: self.$showingModal)
            }
        }
    }
}

I have created a similar enum(not wrapped in struct) in other places in my app and it works fine since the view does not require any inputs. However in this case, CustomActionView expects messageText, viewStyle and a binding property, so I wrapped it within a struct thinking I can assign property values from struct and it will work.

But with this design I am getting the following error and similar error for other 2 properties too:

Value of type 'Destinations.CustomDestinations' has no member 'messageText'

I am not able to store properties within enum either.

Can we pass values to view's within enum?

Note: I am working on watch app with min watchOS version as 7.0.

Thanks!

CodePudding user response:

Well, first, the way that you're using @Binding in a struct that isn't a view is bound to bite you back at some point. Bindings are SwiftUI-specific and using them outside of that context is bound to cause bugs and unexpected behaviours at some point.

If you want to pass in some data when using enum cases, you must use associate values:

enum Foo {
    case number(Int)
    case text(String)
}

switch Foo.text("Hello, World") {
case .number(let number):
    print("the number is: \(number)")

case .text(let text):
    print("the text is: \(text)")
}

That said, using associated values is incompatible with raw values, which means you'd need to drop the Int and CaseIterable conformance.

I think it's over complicating things when Destinations is not a view, so why not just make it a view?

struct Destinations: View {
    var messageText: String = ""
    var viewStyle: Int = 0

    @Binding var showingModal: Bool

    var body: some View {
        CustomActionsView(
            mainMessageText: messageText,
            viewStyle: 0,
            showingModal: $showingModal
        )
    }
}

And then, you can drop the whole enum dance.

CodePudding user response:

In such cases we can use function instead calculable property and get needed things via arguments, like

enum CustomDestinations: Int, CaseIterable, Hashable {
    case view1 = 0, view2 = 1, view3 = 2

    @ViewBuilder 
    func view(message: String, isModal: Binding<Bool>) -> some View {
        switch self {
        case .view1: CustomActionsView(mainMessageText: message, viewStyle: 0, showingModal: isModal)
        case .view2: CustomActionsView(mainMessageText: message, viewStyle: 1, showingModal: isModal)
        case .view3: CustomActionsView(mainMessageText: message, viewStyle: 2, showingModal: isModal)
        }
    }
}
  • Related