Xcode 14 “Publishing changes from within view updates is not allowed, this will cause undefined behavior”

Published on: September 7, 2022

Dear reader, if you've found this page you're probably encountering the error from the post title. Let me start by saying this post does not offer you a quick fix. Instead, it serves to show you the instance where I ran into this issue in Xcode 14, and why I believe this issue is a bug and not an actual issue. I've last tested this with Xcode 14.0's Release Candidate. I've filed feedback with Apple, the feedback number is FB11278036 in case you want to duplicate my issue.

Some of the SwiftUI code that I've been using fine for a long time now has recently started coming up with this purple warning.

Screenshot of "Publishing changes from within view updates is not allowed, this will cause undefined behavior." purple warning

Initially I thought that there was a chance that I was, in fact, doing something weird all along and I started chipping away at my project until I had something that was small enough to only cover a few lines, but still complex enough to represent the real world.

In my case, the issue happened with the following code:

class SampleObject: ObservableObject {
    @Published var publishedProp = 1337

    func mutate() {
        publishedProp = Int.random(in: 0...50)
    }
}

struct CellView: View {
    @ObservedObject var dataSource: SampleObject

    var body: some View {
        VStack {
            Button(action: {
                dataSource.mutate()
            }, label: {
                Text("Update property")
            })

            Text("\(dataSource.publishedProp)")
        }
    }
}

struct ContentView: View {
    @StateObject var dataSource = SampleObject()

    var body: some View {
        List {
            CellView(dataSource: dataSource)
        }
    }
}

This code really does nothing outrageous or weird. A tap on a button will simply mutate an @Published property, and I expect the list to update. Nothing fancy. However, this code still throws up the purple warning. Compiling this same project in Xcode 13.4.1 works fine, and older Xcode 14 betas also don't complain.

At this point, it seems like this might be a bug in List specifically because changing the list to a VStack or LazyVStack in a ScrollView does not give me the same warning. This tells me that there is nothing fundamentally wrong with the setup above.

Another thing that seems to work around this warning is to change the type of button that triggers the action. For example, using a bordered button as shown below also runs without the warning:

Button(action: {
    dataSource.mutate()
}, label: {
    Text("Update property")
}).buttonStyle(.bordered)

Or if you want your button to look like the default button style on iOS, you can use borderless:

Button(action: {
    dataSource.mutate()
}, label: {
    Text("Update property")
}).buttonStyle(.borderless)

It kind of looks like anything except a default Button in a List is fine.

For those reasons, I sadly cannot give you a proper fix for this issue. The things I mentioned are all workarounds IMO because the original code should work. All I can say is please file a feedback ticket with Apple so we can hopefully get this fixed, documented, or otherwise explained. I'll be requesting a code level support ticket from Apple to see if an Apple engineer can help me figure this out.

Once I have a better picture of exactly what's happening I will update this post.

Categories

SwiftUI