Home > database >  Is there penalty in using too many EnvironmentObject?
Is there penalty in using too many EnvironmentObject?

Time:06-29

I'm writing a keyboard extension which resources are more limited. I am trying to pick a code structure and need some help. The project will have multiple classes or struct to encapsulate a fair amount of data, with functions to manipulate them. There will be one or two variables in each class to define the state which UI will need to be updated accordingly.

Two design choices

  1. Make each class as EnvironmentObject and publish the variables the UI needs to observe. This would mean I need to set ~10 classes as EnvironmentObject.

  2. Consolidate the state variables to one class which is set as EnvironmentObject. It is less clean but I will only need to set 1 class as EnvironmentObject.

My question is: Is there any penalty in picking 1?

CodePudding user response:

Everybody's application will be slightly different in terms of setup.

However, the ObservableObject protocol means that each object – whether declared as an environment object or a state object – has a single objectWillChange() method which fires whenever any observable attribute changes. The @Published property wrapper automatically handles that for us.

But that message only tells the SwiftUI rendering system that something in the object has changed; the rendering system then has to work out whether any of the changed object's new properties require the UI to be redrawn.

If you have a single environment object with a huge amount of published properties, it is possible that might result in a performance hit. If you split that single object into multiple environment objects, and each view only opts into the environment object it needs to watch in order to redraw itself, you might see some performance improvements, because some views' dependencies would not have changed and so SwiftUI would be able to, in essence, skip over them.

But having multiple objects can have downsides. As a developer, it can be harder to maintain. You would also need to ensure that each environment object was truly independent of all the others (otherwise you'd get cascading updates which would negate any performance improvements, and possibly make things worse). It can sometimes be easier as a developer, too – if you get the separation of functionality right, it can help keep your code organised and maintainable. Getting that sweet spot can be really tricky, though.

So there's a balance to be struck. If performance is turning out to be an issue, Instruments ought to be able to help in terms of deciding where your individual pain points are and how to start addressing them.

But generally, I'd start from the code structure that makes it easier to write and debug for you. It's easier to optimise well-structured code than it is to maintain highly optimised but hard-to-read code!

(Disclaimer: I'm not a deep expert in SwiftUI and Combine internals – the above is gained from my practical application experience, as well as facing similar questions in the world of ReactJS and Redux in the JavaScript world, where single large state objects face similar scale issues)

  • Related