4 ms·
Can someone provide explanation why SwiftUI is slow? My intuition was that it should be extremely fast, especially on the modern MacBooks. I write quite a lot o
by divan 4y ago
Can someone provide explanation why SwiftUI is slow? My intuition was that it should be extremely fast, especially on the modern MacBooks. I write quite a lot of desktop apps in Flutter (or run mobile apps as MacOS builds, because it's easier to develop and debug this way), and I've never had issues like this, but it's hard to believe that Flutter is faster than SwiftUI. I'm confused by this article.
- c-smile 4y agoI don't know internals of SwiftUI that match but if it still using CoreGraphics then it should be slow. CoreGraphics uses CPU rasterization of primitives and that's the problem on modern displays. Retina grade displays have ~9 times more pixels on surface than old 96 ppi monitors. So you need 10 times more performant CPUs for rendering - CPU rasterization is O(Npix) complex - as better (resolution) monitor you have as slow your UI. On the other side games use GPUs (Metal, OpenGL) to render primitives. In that case CPUs just generate lists of primitive definitions in vector forms (polygons, etc.). Rasterization of those primitives is done in parallel by crowd of GPU processors. Therefore, games UI is not tied with monitor resolution directly - same [display] lists are generated by CPU for any monitor resolution. In that respect GPU accelerated UI rendering is O(1) complex.
- dev_tty01 4y agoYou can directly enable the use of Metal with the drawingGroup() API. https://www.hackingwithswift.com/books/ios-swiftui/enabling-high-performance-metal-rendering-with-drawinggroup https://www.hackingwithswift.com/books/ios-swiftui/enabling-... You can also embed a UIViewRepresentable to "manually" embed a metal kit view inside a SwiftUI hierarchy. Basically use SwiftUI to manage most of it, but use metal to handle a bottleneck somewhere. Here is an example: https://developer.apple.com/forums/thread/119112 https://developer.apple.com/forums/thread/119112
- divan 4y agothat sounds reasonable, thank you
- saagarjha 4y agoVery few SwiftUI apps are bottlenecked on CoreGraphics drawing on the CPU.
- luigi23 4y agohaven't read all article, but few factors: - swiftui for macos apps is slower (smaller teams at apple to optimize it, all focus is on ios) - with appkit you'd use reusable views, and swiftui is having hard time with them - with reusable views you model data on view presentation, whereas with swiftui you often need to generate view data ahead of time, for all views (so 400 views can take some time just for data formatting)
- jitl 4y agoIt comes down to understanding the reactivity model - how to define state that can change, and how efficiently the UI updates in response to those state changes. I think the issue the author had with SwiftUI is not understanding the reactivity system, or frequently choosing an expedient option that caused over-rendering - unnecessary re-renders in response to state changes that aren't required for the UX to work correctly from the user's perspective. Even if your UI's actual rendering work takes 1ms to paint, you want to avoid re-calculating busy work, allocation, etc, which can drive poor experience. With a framework like React that provides very few primitives, it's quite clear when the framework will re-render. With a complex framework like SwiftUI, there are many primitives and different ways to represent state, subscribe to updates, etc, and the framework is quite under-documented. After spending 15 hours with SwiftUI, I still don't have a clear understanding of how the system detects a subscription, or what the re-render semantics are. React I would describe this way: 1. Every re-render starts when you setState to a value that does not (!==) equal the current value in a parent component, or a reducer stores a new value internally. 2. Child components of that component will re-render except in two cases: 2a. The child component uses React.memo, and the props passed by the parent are shallow-equal to the previous props 2b. The child component JSX nodes are strict-equal to those returned by the previous render of the parent component, eg a subtree in the parent wrapped in useMemo I can't come up with a similar definition for SwiftUI after 15 hours building an app in it. I need to consider @Binding, @State, ObservableObject, @ObservedObject, projected values. When is the system creating fine-grained subscriptions automatically? When is the system subscribing to an entire object (deeply?). Hard to find a cogent explanation of all the options. Because of my different understanding of these frameworks, I personally write React apps that perform better than most people expect web apps to perform, and SwiftUI apps that perform much worse than people expect Apple native apps to perform.
- SebastianKra 4y agoThe talk "Demystifying SwiftUI" provides a great deal of insight into how SwiftUI performs diffs. Basically, unless an identity is explicitly specified using `.id()`, it uses the static types of your views to determine their identity. Naturally, this has a huge effect on what is re-drawn, but also animations. This is also why AnyView can lead to worse performance - it erases the static type information. [1]: https://developer.apple.com/videos/play/wwdc2021/10022/ https://developer.apple.com/videos/play/wwdc2021/10022/