12.7 C
New York
Saturday, March 29, 2025

ios – ButtonStyle makeBody ViewBuilder triggers PreferenceKey cut back


I’ve an issue with ButtonStyle’s perform makeBody triggers PreferenceKey cut back perform, if I’ve swap or if assertion inside makeBody.

I’ve a code beneath:

struct TestPreferenceKey: PreferenceKey {
    
    static var defaultValue: Int = 0

    static func cut back(worth: inout Int, nextValue: () -> Int) {

        print("cut back worth:", worth)
        print("cut back nextValue:", nextValue())

        worth = nextValue()
    }
}

struct TestButtonStyle: ButtonStyle {

    enum `Kind` {
        case a
        case b
    }

    let kind: `Kind`

    func makeBody(configuration: Configuration) -> some View {
        swap kind {
        case .a:
            configuration.label
        case .b:
            configuration.label
        }
    }
}

struct ButtonView: View {
    var physique: some View {
        Button {

        } label: {
            Textual content("Button")
        }
        .buttonStyle(TestButtonStyle(kind: .a))
    }
}

struct ContentView: View {

    var physique: some View {
        VStack {
            ButtonView()
            ButtonView()
        }
        .onPreferenceChange(TestPreferenceKey.self) { worth in
            print("worth:", worth)
        }
    }
}

And I’ve the subsequent prints in log:

cut back worth: 0
cut back nextValue: 0
worth: 0

As I perceive how PreferenceKey works, I ought to don’t have anything printed out.
And it really works so, if I name completely different perform from ButtonStyle’s makeBody:

struct TestButtonStyle: ButtonStyle {

    enum `Kind` {
        case a
        case b
    }

    let kind: `Kind`

    func makeBody(configuration: Configuration) -> some View {
        switcher(configuration: configuration)
    }

    func switcher(configuration: Configuration) -> some View {
        swap kind {
        case .a:
            configuration.label
        case .b:
            configuration.label
        }
    }
}

Now, I’ve nothing printed out.
However, if I add @ViewBuilder wrapper to switcher perform, I’ve printed out once more:

...
    @ViewBuilder
    func switcher(configuration: Configuration) -> some View {
        swap kind {
        case .a:
            configuration.label
        case .b:
            configuration.label
        }
    }
cut back worth: 0
cut back nextValue: 0
worth: 0

Is it anticipated habits with ViewBuilder? Or is it a bug?
Is it all the time essential to do such a traversal with an extra perform?

If anybody is aware of the reply, it will be a lot appreciated! I’d additionally be pleased about helpful hyperlinks on the subject!

UDP:
If I add .desire for certainly one of Views, I get a incorrect results of TestPreferenceKey worth:

...
var physique: some View {
    VStack {
        ButtonView()
            .desire(
                key: TestPreferenceKey.self,
                worth: 3
            )
        ButtonView()
    }
    .onPreferenceChange(TestPreferenceKey.self) { worth in
            print("worth:", worth)
    }
}

Result’s:

cut back worth: 3
cut back nextValue: 0
worth: 0

Though the TestPreferenceKey worth must be 3.
After all, with out @ViewBuilder on switcher TestPreferenceKey worth is true – 3

Printed out:

worth: 3

Related Articles

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Latest Articles