Clarity on updateTraitsIfNeeded in traitCollectionDidChange

For the method -updateTraitsIfNeeded, if it's ran in traitCollectionDidChange is there a possibility for an infinite loop to trigger because we update the trait and then that triggers another traitCollectionDidChange? I know that the key words are "IfNeeded", but I wanted to make sure that this method forces an update usually once and then doesn't retrigger any traitCollection update logic recursively an infinite amount of time. Any help would be appreciated!

Answered by Frameworks Engineer in 758133022

updateTraitsIfNeeded is safe to call from inside a trait change callback (using the new trait registration methods introduced in iOS 17) or from the deprecated traitCollectionDidChange method. The purpose of doing this would be to immediately update traits (and send any trait change callbacks) for other view controllers and views nested underneath self, so that you could immediately perform other operations that rely on the traitCollection of these descendants being up-to-date. (Remember that traits are updated top-down through the hierarchy, so when you receive trait change callbacks for one view controller or view, any child view controllers or subviews nested deeper haven't been updated yet.)

With that said, it's best to minimize the work you perform directly in the trait change callback, and instead simply invalidate and schedule a future update. For example, in UIView subclasses, if you do your work and updates based on traits inside layoutSubviews, then you can just call setNeedsLayout in response to any trait change.

An example of when you should call updateTraitsIfNeeded is when you have a parent view controller or view that manages the layout of one or more children, and that parent needs to manually measure the size of these children to lay them out (e.g. by calling sizeThatFits or similar on them) — because the preferred size of children may depend on their traits, it's a good idea to call updateTraitsIfNeeded first before sizing those children, so that the measured size is accurate right away.

It's perfectly OK to use updateTraitsIfNeeded when you need to, but try to minimize usage of it in general for best performance.

Accepted Answer

updateTraitsIfNeeded is safe to call from inside a trait change callback (using the new trait registration methods introduced in iOS 17) or from the deprecated traitCollectionDidChange method. The purpose of doing this would be to immediately update traits (and send any trait change callbacks) for other view controllers and views nested underneath self, so that you could immediately perform other operations that rely on the traitCollection of these descendants being up-to-date. (Remember that traits are updated top-down through the hierarchy, so when you receive trait change callbacks for one view controller or view, any child view controllers or subviews nested deeper haven't been updated yet.)

With that said, it's best to minimize the work you perform directly in the trait change callback, and instead simply invalidate and schedule a future update. For example, in UIView subclasses, if you do your work and updates based on traits inside layoutSubviews, then you can just call setNeedsLayout in response to any trait change.

An example of when you should call updateTraitsIfNeeded is when you have a parent view controller or view that manages the layout of one or more children, and that parent needs to manually measure the size of these children to lay them out (e.g. by calling sizeThatFits or similar on them) — because the preferred size of children may depend on their traits, it's a good idea to call updateTraitsIfNeeded first before sizing those children, so that the measured size is accurate right away.

It's perfectly OK to use updateTraitsIfNeeded when you need to, but try to minimize usage of it in general for best performance.

Clarity on updateTraitsIfNeeded in traitCollectionDidChange
 
 
Q