Interesting finding on a #SwiftUI performance issue. Made a sample app to test. With a 6,500 item collection, if I have a List containing a ForEach and call a RowView() within that ForEach that defines the row contents, the body on RowView is called 6,500 times indicating 6,500 rows are rendered.
If the identical contents of that RowView are placed directly inside the ForEach, only 37 rows are initially rendered, when 17 fit on the screen.
I’m unclear why. Would love any insights. #iOSDev
=> More informations about this toot | More toots from babbage@iosdev.space
I appear to have cracked this. By conforming RowView to Equatable
plus then appending to RowView the .equatable()
view modifier, the View loads just 18 rows... only one or two more than initially appear on screen.
Based on this, it seems even the previous 37 was probably rendering all visible views twice...
This looks like a great solution if it lets me continue to use subviews while addressing the performance issue.
UPDATE: See this important explanation: https://indieweb.social/@curtclifton/113273571392595819
=> More informations about this toot | More toots from babbage@iosdev.space
I wondered whether explicitly setting view identifies would also solve this but didn't seem to. I tried multiple combinations of how to set the identifiers on the RowView instances and this did not stop the example from rendering the full 6,500 rows representing the full collection.
I don’t recall coming across this .equatable()
view modifier prev. I am unsure if the lack of this is triggering a bug in SwiftUI or demonstrates expected behaviour. But I bet this is a commonly experienced issue.
=> More informations about this toot | More toots from babbage@iosdev.space
@babbage interesting. It seems to be the same with a List(items) (i.e. without the foreach). I thought equatable was only there to help with the diffing but didn't realize it's necessary for lazy loading as well.
=> More informations about this toot | More toots from chris@m.objc.io
@chris @babbage Equatable is likely the wrong answer here and will be less performant in release builds. I’ll share more details when I get to my office Mac. I suspect you’re running into a DEBUG-only problem, Duncan
=> More informations about this toot | More toots from curtclifton@indieweb.social
@chris @babbage I think the issues here would not appear in a release build.
As of Xcode 16, every SwiftUI view is wrapped in an AnyView in debug builds only. This speeds switching between previews, simulator, and device, but subverts some List optimizations.
Add this custom build setting to the project to override the new behavior:
text/gemini
This content has been proxied by September (3851b).