UPGRADE YOUR SKILLS: Learn advanced Swift and SwiftUI on Hacking with Swift+! >>

DAY 24. Creating Custom View.

Forums > 100 Days of SwiftUI

I created custom view for button. Function passed in there can't be applied, it causes the following error "Modifying state during view update, this will cause undefined behavior." What's the problem?

struct FlagImage: View {
    var image: String
    var function: ()

    var body: some View {
        Button(action: {
            function
        }, label: {
            Image(image)
                .renderingMode(.original)
                .clipShape(Capsule())
                .overlay(Capsule().stroke(Color.black, lineWidth: 1))
                .shadow(color: .black, radius: 2)
        })
    }
}

In the main View it's called this way

.............
ForEach(0 ..< 3) { number in
    FlagImage(image: self.countries[number].lowercased(), function: flagTapped(number))
}
.............

3      

You are passing the result of a function into the FlagImage struct, rather than a func itself, which is what you seem to be wanting to do. I think that's what's causing the warning.

3      

What's happening here is that in flagTapped you are updating the score (presumably) which means you are updating the State of ContentView. Which in turn means, your ForEach for the FlagView "might" get updated too and Xcode doesn't know if this will be a problem. So while technically it recognizes that there are no errors, it cannot predict ahead of time if it won't be an issue.

This warning pops up when you have a state change inside the body of a view. Whereas if you just had a Button inside your ForEach, then the state change caused by flagTapped will be inside the "onTapGesture" of the button, and therefore will certainly not be called until after the view re-evaluates the rendering.

FlagView is a View, not a button. We know that's what it is being used for, but as far as the compiler is concerned, it's a View, because that's how it's declared.

edit: more of a P.S. but the above is basically an elaboration on the previous comment.

4      

So, Buttons can't be be used as custom View? (Cause function I passed didn't work.) Or, what's the way to create custom buttons/ controllers/ custom Views with controllers, so the actions I pass work in the main View ?

@roosterboy , How to pass a func itself?

3      

You most certainly can create them in a similar way to what you have done. The way it is usually done though is

let function: () -> Void

The key however, is that the function being passed does not change state. That's where your warning is. In the change of state.

Also, you might want to look at ButtonStyle and how to use that. In this particular case, there is no real benefit in extracting the entirety of the button in it's own custom view, so you might be better off using a custom style instead.

Maybe you can find answers here: https://swiftwithmajid.com/2020/02/19/mastering-buttons-in-swiftui/

4      

BUILD THE ULTIMATE PORTFOLIO APP Most Swift tutorials help you solve one specific problem, but in my Ultimate Portfolio App series I show you how to get all the best practices into a single app: architecture, testing, performance, accessibility, localization, project organization, and so much more, all while building a SwiftUI app that works on iOS, macOS and watchOS.

Get it on Hacking with Swift+

Sponsor Hacking with Swift and reach the world's largest Swift community!

Archived topic

This topic has been closed due to inactivity, so you can't reply. Please create a new topic if you need to.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.