Home IOS Development Xcode 14 “Publishing modifications from inside view updates just isn’t allowed, this may trigger undefined habits” – Donny Wals

Xcode 14 “Publishing modifications from inside view updates just isn’t allowed, this may trigger undefined habits” – Donny Wals

0
Xcode 14 “Publishing modifications from inside view updates just isn’t allowed, this may trigger undefined habits” – Donny Wals

[ad_1]

Printed on: September 7, 2022

UPDATE FOR XCODE 14.1: This situation seems to have been partially mounted in Xcode 14.1. Some occurences of the warning are mounted, others aren’t. On this put up I am accumulating conditions me and others run into and observe whether or not they’re mounted or not. If in case you have one other pattern that you simply suppose is analogous, please ship a pattern of your code on Twitter as a Github Gist.


Expensive reader, in case you’ve discovered this web page you are in all probability encountering the error from the put up title. Let me begin by saying this put up does not give you a fast repair. As an alternative, it serves to point out you the occasion the place I bumped into this situation in Xcode 14, and why I imagine this situation is a bug and never an precise situation. I’ve final examined this with Xcode 14.0’s Launch Candidate. I’ve filed suggestions with Apple, the suggestions quantity is FB11278036 in case you wish to duplicate my situation.

A few of the SwiftUI code that I have been utilizing high-quality for a very long time now has lately began arising with this purple warning.

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

Initially I believed that there was an opportunity that I used to be, actually, doing one thing bizarre all alongside and I began chipping away at my challenge till I had one thing that was sufficiently small to solely cowl just a few strains, however nonetheless complicated sufficient to signify the actual world.

On this put up I’ve collected some instance of the place I and different encounter this situation, together with whether or not it has been mounted or not.

[Fixed] Purple warnings when updating an @Printed var from a Button in a Listing.

In my case, the problem occurred with the next code:

class SampleObject: ObservableObject {
    @Printed var publishedProp = 1337

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

struct CellView: View {
    @ObservedObject var dataSource: SampleObject

    var physique: some View {
        VStack {
            Button(motion: {
                dataSource.mutate()
            }, label: {
                Textual content("Replace property")
            })

            Textual content("(dataSource.publishedProp)")
        }
    }
}

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

    var physique: some View {
        Listing {
            CellView(dataSource: dataSource)
        }
    }
}

This code actually does nothing outrageous or bizarre. A faucet on a button will merely mutate an @Printed property, and I anticipate the listing to replace. Nothing fancy. Nevertheless, this code nonetheless throws up the purple warning. Compiling this similar challenge in Xcode 13.4.1 works high-quality, and older Xcode 14 betas additionally do not complain.

At this level, it looks like this could be a bug in Listing particularly as a result of altering the listing to a VStack or LazyVStack in a ScrollView doesn’t give me the identical warning. This tells me that there’s nothing essentially fallacious with the setup above.

One other factor that appears to work round this warning is to alter the kind of button that triggers the motion. For instance, utilizing a bordered button as proven beneath additionally runs with out the warning:

Button(motion: {
    dataSource.mutate()
}, label: {
    Textual content("Replace property")
}).buttonStyle(.bordered)

Or if you need your button to appear to be the default button fashion on iOS, you need to use borderless:

Button(motion: {
    dataSource.mutate()
}, label: {
    Textual content("Replace property")
}).buttonStyle(.borderless)

It sort of seems to be like something besides a default Button in a Listing is ok.

For these causes, I sadly can not provide you with a correct repair for this situation. The issues I discussed are all workarounds IMO as a result of the unique code ought to work. All I can say is please file a suggestions ticket with Apple so we will hopefully get this mounted, documented, or in any other case defined. I will be requesting a code degree assist ticket from Apple to see if an Apple engineer may also help me determine this out.

Animating a map’s place in SwiftUI

A Map in SwiftUI is offered utilizing the next code:

struct ContentView: View {
    @State var currentMapRegion = MKCoordinateRegion(middle: CLLocationCoordinate2D(latitude: 10.0, longitude: 0.0), span: MKCoordinateSpan(latitudeDelta: 100, longitudeDelta: 100))

    var physique: some View {
        VStack {
            Map(coordinateRegion: $currentMapRegion, annotationItems: allFriends) { buddy in
                MapAnnotation(coordinate: CLLocationCoordinate2D(latitude: 0, longitude: 0)) {
                    Circle()
                        .body(width: 20, top: 20)
                        .foregroundColor(.purple)
                }
            }
        }
        .ignoresSafeArea()
    }
}

Discover how the Map takes a Binding for its coordinateRegion. Which means that every time the map modifications what we’re , our @State can replace and the opposite method round. We are able to assign a brand new MKCoordinateRegion to our @State property and the Map will replace to point out the brand new location. It does this with out animating the change. So as an example we do wish to animate to a brand new place. For instance, by doing the next:

var physique: some View {
    VStack {
        Map(coordinateRegion: $currentMapRegion, annotationItems: allFriends) { buddy in
            MapAnnotation(coordinate: CLLocationCoordinate2D(latitude: buddy.cityLatitude ?? 0, longitude: buddy.cityLongitude ?? 0)) {
                Circle()
                    .body(width: 20, top: 20)
                    .foregroundColor(.purple)
            }
        }
    }
    .ignoresSafeArea()
    .onAppear {
        DispatchQueue.foremost.asyncAfter(deadline: .now() + 3) {
            withAnimation {
                currentMapRegion = MKCoordinateRegion(middle: CLLocationCoordinate2D(latitude: 80, longitude: 80),
                                                      span: MKCoordinateSpan(latitudeDelta: 100, longitudeDelta: 100))
            }
        }
    }
}

This code applies some delay after which finally strikes the map to a brand new place. The animation is also triggered by a Button or actually anything; how we set off the animation is not the purpose.

When the animation runs, we see heaps and many warnings within the console (187 for me…) and so they all say [SwiftUI] Publishing modifications from inside view updates just isn't allowed, this may trigger undefined habits..

We’re clearly simply updating our currentMapRegion simply as soon as, and placing print statements within the onAppear tells us that the onAppear and the withAnimation block are all known as precisely as soon as.

I suspected that the Map itself was updating its binding to animate from one place to the following so I modified the Map setup code somewhat:

Map(coordinateRegion: Binding(get: {
    self.currentMapRegion
}, set: { newValue, _ in
    print("(Date()) assigning new worth (newValue)")
    self.currentMapRegion = newValue
}), annotationItems: allFriends) { buddy in
    MapAnnotation(coordinate: CLLocationCoordinate2D(latitude: buddy.cityLatitude ?? 0, longitude: buddy.cityLongitude ?? 0)) {
        Circle()
            .body(width: 20, top: 20)
            .foregroundColor(.purple)
    }
}

As an alternative of instantly binding to the currentMapRegion property, I made a customized occasion of Binding that enables me to intercept any write operations to see what number of happen and why. Operating the code with this in place, yields an fascinating end result:

2022-10-26 08:38:39 +0000 assigning new worth MKCoordinateRegion(middle: __C.CLLocationCoordinate2D(latitude: 62.973218679210305, longitude: 79.83448028564462), span: __C.MKCoordinateSpan(latitudeDelta: 89.49072082474844, longitudeDelta: 89.0964063502501))
2022-10-26 10:38:39.169480+0200 MapBug[10097:899178] [SwiftUI] Publishing modifications from inside view updates just isn't allowed, this may trigger undefined habits.
2022-10-26 10:38:39.169692+0200 MapBug[10097:899178] [SwiftUI] Publishing modifications from inside view updates just isn't allowed, this may trigger undefined habits.
2022-10-26 10:38:39.169874+0200 MapBug[10097:899178] [SwiftUI] Publishing modifications from inside view updates just isn't allowed, this may trigger undefined habits.
2022-10-26 08:38:39 +0000 assigning new worth MKCoordinateRegion(middle: __C.CLLocationCoordinate2D(latitude: 63.02444217894995, longitude: 79.96021270751967), span: __C.MKCoordinateSpan(latitudeDelta: 89.39019889305074, longitudeDelta: 89.09640635025013))
2022-10-26 10:38:39.186402+0200 MapBug[10097:899178] [SwiftUI] Publishing modifications from inside view updates just isn't allowed, this may trigger undefined habits.
2022-10-26 10:38:39.186603+0200 MapBug[10097:899178] [SwiftUI] Publishing modifications from inside view updates just isn't allowed, this may trigger undefined habits.
2022-10-26 10:38:39.186785+0200 MapBug[10097:899178] [SwiftUI] Publishing modifications from inside view updates just isn't allowed, this may trigger undefined habits.
2022-10-26 08:38:39 +0000 assigning new worth MKCoordinateRegion(middle: __C.CLLocationCoordinate2D(latitude: 63.04063284402105, longitude: 80.00000000000011), span: __C.MKCoordinateSpan(latitudeDelta: 89.35838016069978, longitudeDelta: 89.0964063502501))
2022-10-26 10:38:39.200000+0200 MapBug[10097:899178] [SwiftUI] Publishing modifications from inside view updates just isn't allowed, this may trigger undefined habits.
2022-10-26 10:38:39.200369+0200 MapBug[10097:899178] [SwiftUI] Publishing modifications from inside view updates just isn't allowed, this may trigger undefined habits.
2022-10-26 10:38:39.200681+0200 MapBug[10097:899178] [SwiftUI] Publishing modifications from inside view updates just isn't allowed, this may trigger undefined habits.

That is only a small a part of the output in fact however we will clearly see that the print from the customized Binding is executed in between warnings.

I can solely conclude that this must be some situation in Map that we can not clear up ourselves. You would possibly be capable to tweak the customized binding a bunch to throttle how typically it really updates the underlying @State however I am unsure that is what we should always need…

In the event you’re seeing this situation too, you’ll be able to reference FB11720091 in suggestions that you simply file with Apple.

Large because of Tim Isenman for sending me this pattern.



[ad_2]

LEAVE A REPLY

Please enter your comment!
Please enter your name here