I finally have an understanding of what is happening here.
Credit where credit is due because ChatGPT put me on the right path to fix this.
It said to check in .task if any of my Object's properties were being changed, EVEN WITH THE SAME VALUE.
Previously I had some computed properties that were being called too much so I compute them in a few places manually, including .task/.onAppear.
I tried adding seatbelts around those assignments to do nothing if the values weren't changing.
After doing that the loop is gone.
I'm not quite understanding why this code was fine in iOS 17 but goes off the rails in iOS 18.
Best guesses:
Assigning a Published property the same value in iOS 17 does NOT trigger a View update but with iOS 18 it does?
The order/sequence/etc of .task/.onAppear changed and it made this shortcoming of my app apparent.
This whole summer I thought my problem was related to the "double push" to the NavigationStack that was happening if your NavigationPath was in an Observable or ObservedObject. (FB14270042)
When I moved my NavigationPath to its own class and printChanges STILL reported that it thought my original object was changing constantly I realized something else was happening.
Post
Replies
Boosts
Views
Activity
I've made multiple design changes that I hoped would solve this problem but I still have it.
My app actually no longer has a tabs. I also moved the array used for navigation from my ObservableObject to its own dedicated Observable.
The problem still happens relatively the same.
If I navigate to my Settings View (which used to be a separate tab) and then navigate into another View the infinite loops starts and won't stop.
With the iPad simulator (and my iPad) I can still do a little with the app, although it is very slow. With the iPhone simulator the CPU of the simulator goes to over 100% and locks up.
I did get this tip: "A workaround that I’ve seen for some examples is to make the view being pushed Equatable, (comforming properly to the protocol) and then do .equatable() in the destination." Unfortunately that does not seem to fix the problem in my experiments.
printChanges will show that it thinks that my ObservableObject is continuing to change:
StartingView: @self, _weatherData changed.
I'm becoming gravely concerned considering how close to Sept 9 we are. It's greatly affecting my ability to test my app and I don't feel like I could release it in this state.
I think I have a way to address this.
I changed the accessibilityLabel to be "Favorite Button" and added accessibilityValue with the current value.
After that VoiceOver is no longer always saying the toggle is off.
Button {
showFavActions()
} label: {
Image(systemName: SFSymbolShortcut.star.rawValue)
.symbolVariant(weatherData.currentlyFavIndex == nil ?
.none : .fill)
}
.buttonStyle(.plain)
.accessibilityLabel(Text("Favorite Button"))
.accessibilityHint(Text(weatherData.currentlyFavIndex == nil ?
"Add to favorites." :
"Remove from favorites."))
.accessibilityInputLabels(["Favorite"])
.accessibilityAddTraits(.isToggle) // iOS 17
.accessibilityValue(weatherData.currentlyFavIndex == nil ?
"Not a favorite location." :
"Favorite location.")
No change with Version 16.0 beta 6 (16A5230g).
No change with Version 16.0 beta 6 (16A5230g).
No change with Version 16.0 beta 5 (16A5221g).
No change with Version 16.0 beta 5 (16A5221g).
My celebration was short lived because I found another situation that triggers the same endless loop behavior.
I have a @Published property that controls what sheet is launched. Populating it causes this same loop. And this time removing @Published makes the sheet logic stop working.
So I don't have a workaround any more.
I figured out how to make the endless loop stop. So I now have workarounds to both scenarios.
I am able to recreate the "double push" after navigation behavior in a sample project. I am able to stop it by removing @Published from my property that holds a navigation path in my @ObservableObject.
Also, adding @ObservationIgnored to a similar property in an @Observable apparently works also.
I am NOT able to recreate the endless calling of .onAppear/.task in a sample project. I am able to stop it in my app by removing @Published from my property that holds the selected tab in my @ObservableObject.
This is code that is functioning without an issue with iOS 17. I only encountered these problems when building for iOS 18.
Some more context:
The first time I encountered this endless loop was in this scenario:
App launches and brings up default tab which I call my starting view. I found that when I switched to another tab but then went back to my first tab my .onAppear for the starting view would get called endlessly.
I “fixed” this by switching the .onAppear to .task instead BUT .task ended up being called twice in this same scenario. Still not ideal but better than endless.
I was able to recreate the double push part of the problem so I opened feedback.
FB14270042
FYI to anyone who might reference this thread. SnowfallAmount has been added to HourWeather in iOS 18. I can now rip out my janky code to convert the liquid amount to snowfall amount.
Thank you for addressing this.
I'm bumping my old thread with more info. I did a deep dive into the hourly WeatherKit data that is returned. I've been using precipitationAmount to report the snow amout, but there's actually a property returned called snowfallAmount!! And it appears to contain values that are what I have been expecting for snow.
WeatherKit.HourWeather(date: 2024-01-09 15:00:00 +0000, cloudCover: 0.98, cloudCoverLow: 0.0, cloudCoverMid: 0.0, cloudCoverHigh: 0.0, condition: Heavy Snow, symbolName: "cloud.snow", dewPoint: -0.44 °C, humidity: 0.96, isDaylight: true, precipitation: snow, precipitationChance: 0.61, precipitationAmount: 2.75 mm, snowfallAmount: 27.16 mm, pressure: 1018.33 mbar, pressureTrend: Falling, temperature: 0.16 °C, apparentTemperature: -4.72 °C, uvIndex: WeatherKit.UVIndex(value: 1, category: Low), visibility: 778.16 m, wind: WeatherKit.Wind(compassDirection: Southeast, direction: 127.0 °, speed: 17.97 km/h, gust: Optional(51.98 km/h))),
BUT if you look at the HourWeather in SwiftUI the snowfall amount is missing. You see the precipitation, precipitationChance, and precipitationAmount that are before it in the raw data and the pressure, pressureTrend, etc that follow it.
snowFall isn't in an extension, Xcode autocomplete doesn't know about it, doesn't compile, etc.
Either this is a major omission or I'm completely misunderstanding something.
I filed FB13521886
Had the same question and also couldn't find an answer. Try passing an empty string as the dialog. That seems to do the trick.
I'm starting to get support emails from users running the iOS 17 beta reporting that they can't retrieve weather forecasts with my app.