Printed on: September 7, 2022
UPDATE FOR XCODE 14.1: This subject seems to have been partially fastened in Xcode 14.1. Some occurences of the warning are fastened, others aren’t. On this publish I am amassing conditions me and others run into and observe whether or not they’re fastened or not. You probably 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, for those who’ve discovered this web page you are in all probability encountering the error from the publish title. Let me begin by saying this publish does not give you a fast repair. As an alternative, it serves to point out you the occasion the place I bumped into this subject in Xcode 14, and why I consider this subject is a bug and never an precise subject. 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 need to duplicate my subject.
Among the SwiftUI code that I have been utilizing wonderful for a very long time now has lately began developing with this 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 undertaking till I had one thing that was sufficiently small to solely cowl a couple of strains, however nonetheless complicated sufficient to symbolize the actual world.
On this publish I’ve collected some instance of the place I and different encounter this subject, together with whether or not it has been fastened or not.
[Fixed] Purple warnings when updating an @Printed var from a Button in a Checklist.
In my case, the difficulty 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 {
Checklist {
CellView(dataSource: dataSource)
}
}
}
This code actually does nothing outrageous or bizarre. A faucet on a button will merely mutate an @Printed
property, and I count on the listing to replace. Nothing fancy. Nonetheless, this code nonetheless throws up the purple warning. Compiling this similar undertaking in Xcode 13.4.1 works wonderful, and older Xcode 14 betas additionally do not complain.
At this level, it looks as if this is likely to be a bug in Checklist
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 basically flawed with the setup above.
One other factor that appears to work round this warning is to vary the kind of button that triggers the motion. For instance, utilizing a bordered button as proven under additionally runs with out the warning:
Button(motion: {
dataSource.mutate()
}, label: {
Textual content("Replace property")
}).buttonStyle(.bordered)
Or if you’d like your button to appear like the default button type on iOS, you should use borderless
:
Button(motion: {
dataSource.mutate()
}, label: {
Textual content("Replace property")
}).buttonStyle(.borderless)
It form of appears like something besides a default Button
in a Checklist
is ok.
For these causes, I sadly can not offer you a correct repair for this subject. 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 fastened, documented, or in any other case defined. I will be requesting a code stage help ticket from Apple to see if an Apple engineer can assist me determine this out.
Animating a map’s place in SwiftUI
A Map in SwiftUI is introduced utilizing the next code:
struct ContentView: View {
@State var currentMapRegion = MKCoordinateRegion(heart: CLLocationCoordinate2D(latitude: 10.0, longitude: 0.0), span: MKCoordinateSpan(latitudeDelta: 100, longitudeDelta: 100))
var physique: some View {
VStack {
Map(coordinateRegion: $currentMapRegion, annotationItems: allFriends) { good friend in
MapAnnotation(coordinate: CLLocationCoordinate2D(latitude: 0, longitude: 0)) {
Circle()
.body(width: 20, top: 20)
.foregroundColor(.pink)
}
}
}
.ignoresSafeArea()
}
}
Discover how the Map
takes a Binding
for its coordinateRegion
. Because of this every time the map adjustments what we’re taking a look at, our @State
can replace and the opposite approach 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 instance we do need to animate to a brand new place. For instance, by doing the next:
var physique: some View {
VStack {
Map(coordinateRegion: $currentMapRegion, annotationItems: allFriends) { good friend in
MapAnnotation(coordinate: CLLocationCoordinate2D(latitude: good friend.cityLatitude ?? 0, longitude: good friend.cityLongitude ?? 0)) {
Circle()
.body(width: 20, top: 20)
.foregroundColor(.pink)
}
}
}
.ignoresSafeArea()
.onAppear {
DispatchQueue.fundamental.asyncAfter(deadline: .now() + 3) {
withAnimation {
currentMapRegion = MKCoordinateRegion(heart: 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 the rest; 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 adjustments 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 referred to 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 a bit of:
Map(coordinateRegion: Binding(get: {
self.currentMapRegion
}, set: { newValue, _ in
print("(Date()) assigning new worth (newValue)")
self.currentMapRegion = newValue
}), annotationItems: allFriends) { good friend in
MapAnnotation(coordinate: CLLocationCoordinate2D(latitude: good friend.cityLatitude ?? 0, longitude: good friend.cityLongitude ?? 0)) {
Circle()
.body(width: 20, top: 20)
.foregroundColor(.pink)
}
}
As an alternative of instantly binding to the currentMapRegion
property, I made a customized occasion of Binding
that permits me to intercept any write operations to see what number of happen and why. Working the code with this in place, yields an fascinating outcome:
2022-10-26 08:38:39 +0000 assigning new worth MKCoordinateRegion(heart: __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 adjustments 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 adjustments 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 adjustments from inside view updates just isn't allowed, this may trigger undefined habits.
2022-10-26 08:38:39 +0000 assigning new worth MKCoordinateRegion(heart: __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 adjustments 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 adjustments 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 adjustments from inside view updates just isn't allowed, this may trigger undefined habits.
2022-10-26 08:38:39 +0000 assigning new worth MKCoordinateRegion(heart: __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 adjustments 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 adjustments 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 adjustments 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 needs to be some subject in Map
that we can not resolve ourselves. You may 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 must always need…
If you happen to’re seeing this subject too, you possibly can reference FB11720091
in suggestions that you simply file with Apple.
Large due to Tim Isenman for sending me this pattern.