Search code examples
iosswiftuser-interfaceuikituitraitcollection

‘traitCollectionDidChange’ was deprecated in iOS 17.0. How do I use the replacement?


I am trying to work with this function but it does not work with iOS 17. I want to make a change every time I switch between dark and light mode.

This is my function:

override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
    super.traitCollectionDidChange(previousTraitCollection)

    // Check if the user interface style has changed
    if self.traitCollection.hasDifferentColorAppearance(comparedTo: previousTraitCollection) {
        // User interface style has changed (light to dark or vice versa)
        if self.traitCollection.userInterfaceStyle == .light {
            // Code to execute in light mode
            print("App switched to light mode")
        } else {
            // Code to execute in dark mode
            print("App switched to dark mode")
        }
    }
}

This is the issue:

‘traitCollectionDidChange’ was deprecated in iOS 17.0: Use the trait change registration APIs declared in the UITraitChangeObservable protocol

Should I use registerForTraitChanges(_:handler:) or registerForTraitChanges(_:target:action:) instead? I don't know how to use it.


Solution

  • traitCollectionDidChange is deprecated as of iOS 17.0. The solution depends on your app's deployment target. If your app's deployment target is older than iOS 17.0 (Xcode 15 supports back to iOS 12) then it's perfectly fine to continue using traitCollectionDidChange. It will continue to be called even on a device with iOS 17. You won't even get a deprecation warning if you have an older deployment target.

    If your app's deployment target is iOS 17.0 or later then you should not override traitCollectionDidChange since it is now deprecated. As the documentation for traitCollectionDidChange shows, you instead make use of either registerForTraitChanges(_:handler:) or registerForTraitChanges(_:target:action:).

    The documentation for both of the new methods provide examples of how to use them. The key is to find the trait(s) your code wishes to work with.

    In your case you wish to handle a change to UITraitUserInterfaceStyle. You can find the list of traits that you can register for on the page for UIMutableTraits.

    Update your code by removing the use of traitCollectionDidChange and adding the following to viewDidLoad:

    registerForTraitChanges([UITraitUserInterfaceStyle.self], handler: { (self: Self, previousTraitCollection: UITraitCollection) in
        if self.traitCollection.userInterfaceStyle == .light {
            // Code to execute in light mode
            print("App switched to light mode")
        } else {
            // Code to execute in dark mode
            print("App switched to dark mode")
        }
    })
    

    Note that the documentation clearly states that you can safely ignore the return value and you do not need to unregister. You would want to make use of the return value and unregister if you had a case where your registration has a more limited lifetime.

    Your update doesn't need to call hasDifferentColorAppearance(comparedTo:) since the handler code is only going to be called when the user interface style changes in this case.


    Note - if your deployment target is older than iOS 17, do not use both the old and new code since both sets of code will actually be called when run on devices with iOS 17. You would end up having two similar sets of code each wrapped with appropriate if #available checks.