Ancestors

Written by Duncan Babbage on 2024-09-29 at 23:46

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

Toot

Written by Duncan Babbage on 2024-09-30 at 01:38

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

Descendants

Written by Duncan Babbage on 2024-09-30 at 01:41

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

Written by Chris Eidhof on 2024-10-08 at 08:07

@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

Written by Curt Clifton on 2024-10-08 at 12:15

@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

Written by Curt Clifton on 2024-10-08 at 19:58

@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:

Proxy Information
Original URL
gemini://mastogem.picasoft.net/thread/113223944876495780
Status Code
Success (20)
Meta
text/gemini
Capsule Response Time
300.357401 milliseconds
Gemini-to-HTML Time
1.018083 milliseconds

This content has been proxied by September (3851b).