7

I have found that when putting app into background the traitCollectionDidChange method is being called twice and showing that trait collections differ when actually no changes have been made.

- (void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection;

To figure out if appearance style has been switched between Light & Dark mode we have used the hasDifferentColorAppearanceComparedToTraitCollection method.

BOOL hasUserInterfaceStyleChanged = [previousTraitCollection
                                     hasDifferentColorAppearanceComparedToTraitCollection:self.traitCollection];

The problem is that this is always true, and for whatever reason trait collections are different when nothing was changed. See below UserInterfaceStyle is actually different when in reality it isn't.

First Trigger:

previousTraitCollection:

<UITraitCollection: 0x280228c00; UserInterfaceIdiom = Phone, DisplayScale = 2, DisplayGamut = P3, HorizontalSizeClass = Compact, VerticalSizeClass = Regular, UserInterfaceStyle = Light, UserInterfaceLayoutDirection = LTR, ForceTouchCapability = Unavailable, PreferredContentSizeCategory = L, AccessibilityContrast = Normal, UserInterfaceLevel = Base>

self.traitCollection:

<UITraitCollection: 0x28023b600; UserInterfaceIdiom = Phone, DisplayScale = 2, DisplayGamut = P3, HorizontalSizeClass = Compact, VerticalSizeClass = Regular, UserInterfaceStyle = Dark, UserInterfaceLayoutDirection = LTR, ForceTouchCapability = Unavailable, PreferredContentSizeCategory = L, AccessibilityContrast = Normal, UserInterfaceLevel = Base>

Second Trigger:

previousTraitCollection:

<UITraitCollection: 0x28023b600; UserInterfaceIdiom = Phone, DisplayScale = 2, DisplayGamut = P3, HorizontalSizeClass = Compact, VerticalSizeClass = Regular, UserInterfaceStyle = Dark, UserInterfaceLayoutDirection = LTR, ForceTouchCapability = Unavailable, PreferredContentSizeCategory = L, AccessibilityContrast = Normal, UserInterfaceLevel = Base>

self.traitCollection:

<UITraitCollection: 0x28027d800; UserInterfaceIdiom = Phone, DisplayScale = 2, DisplayGamut = P3, HorizontalSizeClass = Compact, VerticalSizeClass = Regular, UserInterfaceStyle = Light, UserInterfaceLayoutDirection = LTR, ForceTouchCapability = Unavailable, PreferredContentSizeCategory = L, AccessibilityContrast = Normal, UserInterfaceLevel = Base>

On the second trigger now trait collections have been reversed but still differ. In this scenario the very first trait collection and the very last trait collection are the correct ones.

Is this a bug on Apple's end? Why is traitCollectionDidChange being called twice when just putting app into background.

Evan
  • 101
  • 7

2 Answers2

14

This is actually a feature: iOS is doing multiple snapshots of your app's UI that will be presented in the App Switcher. And since the user could change to Dark Mode while your app is in the background, iOS does snapshots in both interface styles to always show the correct one.

Frank Rupprecht
  • 9,191
  • 31
  • 56
  • 1
    Surely something is still wrong here though? Is there a correct way to accurately detect that appearance mode has changed instead of this, so we only trigger updates when absolutely necessary? – Evan Aug 14 '20 at 08:58
  • Seems correct to me: The system takes a screenshot of your Light UI, switches to Dark (first trigger), takes a screenshot (off-screen), and switches back to Light (second trigger). And I think it would be good to handle this scenario accordingly and not try to avoid it. Or are you running into issues? – Frank Rupprecht Aug 15 '20 at 19:04
9

check if UIApplication.shared.applicationState != .background to avoid doing stuff while app snapshots are being taken when going to background

Tomer Even
  • 4,820
  • 2
  • 30
  • 36