Home > OS >  Is a StateObject more performant when instantiated in a View instead of the top-level App?
Is a StateObject more performant when instantiated in a View instead of the top-level App?

Time:12-04

I've observed performance differences based on the location of my instantiated StateObject. Specifically, I noticed that when my top-level View owns the StateObject, my app's usage on the main thread decreases by ~5%. For some reason, instantiating this StateObject in a SwiftUI App is less performant. My expectation is that performance would be identical since nothing else changed.

While that 5% might not seem like much, the result might be 10-15% higher CPU utilization on some devices. It's worth nothing that in my StateObject, I've defined a CADisplayLink which runs a callback on every frame, so this is where most of the compute gets used.

For some reason, this:

@main
struct MyApp: App {    
    var body: some Scene {
        WindowGroup {
            MyView()
        }
    }
}

struct MyView: View {
    @StateObject var someStateObject = SomeStateObject()

    var body: some View {
        Text("Hello World")
    }
}

Is more performant than this:

@main
struct MyApp: App {
    @StateObject var someStateObject = SomeStateObject()
    
    var body: some Scene {
        WindowGroup {
            MyView()
        }
    }
}

struct MyView: View {
    var body: some View {
        Text("Hello World")
    }
}

Is there something about SwiftUI's App that would create these performance differences?

CodePudding user response:

It's difficult to say without more information about the specifics of your StateObject and the differences in performance you're observing. However, there are a few potential reasons why instantiating a StateObject in a View might lead to better performance than instantiating it in the top-level App:

  • If the StateObject is only used by a specific View, instantiating it in that View allows SwiftUI to optimize its usage by only initializing the StateObject when it's actually needed. In contrast, if the StateObject is instantiated at the top-level App, it will be initialized even if it's not used by all of the views in your app.

  • If the StateObject is managing a resource (e.g. a network connection or a file) that is only needed by a specific View, instantiating it in that View allows SwiftUI to release the resource when it's no longer needed. This can help to reduce memory usage and improve performance.

  • If the StateObject is using a CADisplayLink (which triggers a callback on every frame of the display), instantiating it in a View allows SwiftUI to automatically pause and resume the CADisplayLink as needed, depending on whether the View is visible on the screen. This can help to reduce the amount of processing that's done when the View is not visible, which can improve overall performance.

In general, it's a good idea to think about the scope of your StateObject and where it's used in your app, and instantiate it in the most appropriate place. This can help to optimize its usage and improve performance.

CodePudding user response:

It is difficult to say for certain without more information, but there are a few reasons why instantiating a StateObject in a View instead of the top-level App might result in better performance.

One possibility is that the App struct is created and initialized when the app launches, whereas the View struct is only created and initialized when it is first displayed. This means that the StateObject in the App example would be created and initialized even if it is never used, whereas in the View example it would only be created and initialized when the View is displayed. This could result in better performance if the StateObject is not used until later in the app.

Another possibility is that the App struct is a global object that exists for the lifetime of the app, whereas the View struct is only in scope while the View is being displayed. This means that the StateObject in the App example would continue to exist and potentially consume resources even when it is not being used, whereas in the View example it would be deallocated when the View is no longer displayed. This could result in better performance if the StateObject is only needed for a short period of time.

Overall, it is generally best to instantiate objects at the lowest level possible, where they are only created and initialized when they are needed, and deallocated when they are no longer needed. This can help to improve performance by reducing unnecessary resource consumption.

  • Related