Xcode 12, Swift 5.3: @Environment(\.colorScheme) Not Updating

Viewed 2073

I am trying to achieve reading dark mode in my app built in SwiftUI, Xcode 12 and iOS14.

I am using this key to find wether or not it's in light or dark mode: @Environment(\.colorScheme) var colorScheme

My testing device is set to dark mode, but the environment variable is reading light mode.

I have tested this removing the app, reloading XCode, and restarting my Macbook Pro.

User Interface Style is not used since this is iOS14. (SwiftUI: Dark mode not detected when testing on device)

The weird thing is, my testing device (iPhone 11 Pro) renders non-background colored views as dark as they should. So the only thing that isn't updating is the variable colorScheme itself. I am not changing that value anywhere in my app programatically.

I also checked that my info.plist is routed properly in the build settings of the target. I am using a target for the main app, and a target for a widget extension.

What am I Missing?

3 Answers

I just found out why

I am reading @Environment(\.colorScheme) var colorScheme: ColorScheme too early in the apps lifecycle.

When I open the app, I create my data class BEFORE the app had finished initializing. I was calling the @Environment(\.colorScheme) var colorScheme: ColorScheme in this data class.

I tested using @Environment(\.colorScheme) var colorScheme: ColorScheme on a view once the app finished initializing with .onAppear() and it worked as it should have

In my project, I found @Environment(\.colorScheme) var colorScheme Get the color scheme of your software, not the color scheme of the system.

So when you manually change the color scheme of the software itself, @Environment(\.colorScheme) var colorScheme You can’t get the phone’s color scheme again.

Use the following code instead, it will get you the color scheme of the phone

let currentSystemScheme = UITraitCollection.current.userInterfaceStyle

It should be noted that userInterfaceStyle and colorScheme are not the same type, so you may need the following code to convert

func schemeTransform(userInterfaceStyle:UIUserInterfaceStyle) -> ColorScheme {
    if userInterfaceStyle == .light {
        return .light
    }else if userInterfaceStyle == .dark {
        return .dark
    }
    return .light}

I expected it to read Dark when it's set to Dark in the Info.plist. per …

Hmm... Apple's documentation says enumerates the user setting options (see below complete snapshot):

/// The possible types of color schemes, like Dark Mode.
///
/// The color scheme enumerates the user setting options for Light or Dark Mode.
/// It also provides the light or dark options for any particular view when the
/// app wants to override the user setting.
@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *)
public enum ColorScheme : CaseIterable {

    case light

    case dark
Related