Reading about @dimillian's issues with SwiftUI and scroll performance in his Ice Cubes app compared to UIKit, and if I were Apple I'd be flying him down to profile his app and see where SwiftUI could be optimized more/what's going on.

Such a great app and showcase of SwiftUI, and even though complex, media-rich timelines with lots of elements can be complex to get right in UIKit, I think instilling community/developer confidence that "Yeah, SwiftUI can do this too" is really important.

@christianselig @dimillian At the very least I’m sure Apple is profiling it internally to find wins since it’s open source. But yeah, that’d be such a developer win at dub dub if they did something like that.
@jordanmorgan @dimillian I was thinking that too, but quietly poking at things behind the scenes wouldn't be nearly as handy to the community and Thomas. This could be a really cool learning moment for everyone!
@jordanmorgan @dimillian But yeah a WWDC session on “Techniques for improving performance in a popular open source app" would be sooooo cool 😛 A++ would attend
@christianselig @dimillian SO I'm also building an app in SwiftUI and scroll performance is definitely an issue. It seems to be related to loading images. I had to scale them all down =(
@wvabrinskas @christianselig we can brainstorm on it, let me know :). I’m at the part where I’m really at the bottom of the barrel. You feel like SwiftUI Image is the bottleneck?
@dimillian @christianselig That's what was hindering my scroll performance. ESPECIALLY if you're loading images from Data. I built a cache to cache the rendered resized image in an NSCache. I look up each image based on an ID and a requested size. I hade to make them like 400px wide, respecting the aspect ration.
@wvabrinskas @christianselig it if you process the actual decoding in a detached Task it should not be an issue right?
@dimillian @christianselig Turns out to not be true at all lol I tried that. No change at all.

@wvabrinskas @dimillian @christianselig TIL about NSCache. Somehow I never heard about it before…

After spending half an hour on quickly prototyping a cache for my project, I can already see significant improvements. Thank you!

@dimillian @christianselig I would also resize all images to be roughly the size of the view they will be contained in. Resizing images to a fit a view with `.resizable()` in SwiftUI seems to be not great. I use the accelerate framework to resize my images manually for their respective view.
@wvabrinskas @christianselig interesting about the resizing Cc @a_grebenyuk
@dimillian @wvabrinskas @christianselig yes, it's recommended to scale images in the background to exactly match the image view size and disable scaling. Otherwise, there is a bit of a penalty, especially noticeable when images are too small or large for the target view. I'm not sure how relevant it is with the modern GPUs though, but it definitely wouldn't hurt. I got some more info on performance here, but nothing SwiftUI-specific yet https://kean-docs.github.io/nuke/documentation/nuke/performance-guide
Documentation

@a_grebenyuk @dimillian @christianselig It seems to be very relevant even on my 14 pro max lol
@wvabrinskas @dimillian @christianselig went through the thread; I'm just wondering, when you referred to loading from Data, what did you mean? If you perform something like Image(uiImage: UIImage(data: data)) on the main thread, it'll be slow because of decompression (for compressed image formats), not scaling. But when you scale an image, it also triggers decompression. Nuke performs decompression in the background by default. It's table stakes in image frameworks, so shouldn't be an issue.
@a_grebenyuk @dimillian @christianselig Yeah I meant loading from Data like you mentioned. Im just speaking anecdotally. I did discover that performing the Data -> Image on the main thread is still an issue I'm just saying that the scaling might be the culprit for slow scroll performance.
@wvabrinskas @a_grebenyuk @dimillian @christianselig Just to add a bit more to this, is the image caching done on-the-fly as rows appear or in batches? If it’s the former another optimisation point would be to pre-load all the new images in bg, resize to fit the exact image rect in retina and cache them before even triggering any UI change. It’s a better UX to let user wait 0.5s than to face micro-stutters.
@tanmay @a_grebenyuk @dimillian @christianselig That's kind of what I'm doing yeah. As they appear they are rendered and cached in the background async. Then each image fades in when ready.
@wvabrinskas @a_grebenyuk @dimillian @christianselig The fade in part will eat up CPU cycles and add render passes. With each row doing it, it will add up. Maybe try a batched approach. Also some way to cancel the fade-in if row isn’t visible anymore (I think SwiftUI should automatically do this via cv cell re-use but just make sure).
@tanmay @a_grebenyuk @dimillian @christianselig the fade in happens only once. Since it already has an image from the cache. No need to wait for the async load.
@wvabrinskas @a_grebenyuk @dimillian @christianselig yeah what I’m suggesting is try to avoid having a fade-in at all. Every cell doing a fade-in animation adds up.
@tanmay @wvabrinskas @dimillian @christianselig great suggestion. I’d definitely remove all appearance animations. I prefer no animations; they are distracting in a feed. And it’s best to prefetch images. It’s delightful when you scroll, and all media is already there.
@dimillian @wvabrinskas @christianselig AsyncImage (not sure if you’re using the async version) has been a bottleneck for scrolling in the past - check out https://blog.iconfactory.com/2022/09/wallaroo-and-swiftui-3-of-5/
Wallaroo and SwiftUI (3 of 5) • The Breakroom

Now that Wallaroo had a unique and good-looking main gallery view along with nice parallax and blurs and everything, my focus shifted to optimizing scrolling performance. The parallax and lazy custom layout seemed to perform just fine, but rendering the glyphs/buttons on each tile view as well as the actual wallpaper image seemed to be […]

Iconfactory Blog
@christianselig @dimillian yes. but. can you attach sample project to reproduce the issue? please attach sysdiag with exact timestamp when problem occurs. We released new beta, is this problem still an issue? we believe it works as designed, closing this feedback. 🤓🥸
@krzyzanowskim @christianselig every time I link them my GitHub repo lol.
@krzyzanowskim @christianselig oh and you need a Mastodon account with a timeline.
@christianselig I do hope they do. They did in the past with my other open source apps. I have a DTS ticket to be scheduled with them. I hope to have answers!
@dimillian @christianselig for sure they should acknowledge those whose issues majorly help move SwiftUI forward. @dimillian is for sure one of those. He goes all in.
@tarasis @christianselig they did before with MovieSwiftUI :)
@dimillian @christianselig I had missed that; fantastic!
@christianselig @dimillian you are due a double acknowledgment
@christianselig @dimillian the Technical Support Incident is really worth it at this point: https://developer.apple.com/support/technical/
Code-level Support - Support - Apple Developer

Learn how to get code-level support for Apple frameworks, APIs, and tools.

@kamalaitbrahim @christianselig I’ve filled one. Will see.
@dimillian @kamalaitbrahim Plus, I think the project is popular enough and the performance questions salient enough that it warrants more than a ticket, I'd really love to see more of a deep dive from Apple folks
@dimillian @kamalaitbrahim 👏 @christianselig for using your platform to broadcast to the powers that be.

@christianselig @dimillian not sure if this is applicable but there was a recent hackernews post regarding SwiftUI and infinite scrolling.

https://blog.timing.is/swiftui-production-experience-problems-solutions-performance-tips/

https://news.ycombinator.com/item?id=34556370

30,000 lines of SwiftUI in production later: We love it but you know there was going to be a “but”

timing.is shipped this month on the App Store. It was built entirely in SwiftUI. It was in development for 12 months. It would have been less if SwiftUI just gave. Unfortunately, repeatedly it would take.

_blog
@joebarbere @dimillian Helpful but quite different I think, that seems to be about jumping through oodles of "cells" in a short period, where Thomas' seems to be more about the richness/complexity of individual cells (versus the app in this post) and scrolling slowly when not even scrolling that fast necessarily
@christianselig @dimillian how the turn tables: Apple debugging _our_ apps for free.
@christianselig @dimillian confidence is really important and I have… not a lot of it for SwiftUI. I’ve got a pretty rock-solid foundation for the client I’ve been working on, and I’ve been really careful to make sure that everything is cohesive, and yet it *still* feels hacked together. Like… in what world should two navigation bars be visible at once??? SwiftUI always feels like it could turn on me at any moment, stop working, and refuse to tell me why.
@christianselig @dimillian Agreed. Whether we like it or not, SwiftUI is the future and Apple has shown us they aren’t budging. Having a complex, popular app on the App Store using SwiftUI is incredibly important.