KeyChain returns nil for a value that is set

I store the information whether the user has premium subscription in the KeyChain.

I just have a global function called doesUserHavePremium that reads a value from the KeyChain.

It appears that sometimes that value is read from the KeyChain incorrectly—even though I am 100% sure it is set, it returns nil. This happens only when the app was launched, then left for some time (probably screen got locked), and then I reentered the app again without relaunching it from scratch.

I tried the following things:

  • loosening the KeyChain access the the least restrictive
  • the following piece of code to notify UI elements whenfalse/trueis read for that value after previously not being able to access it
let protectedDataAvailabilityNotificationName = UIApplication.protectedDataDidBecomeAvailableNotification

func observeProtectedDataAvailability() {
  let selector = #selector(Self.protectedDataAvailableNotification)
  switch UIApplication.shared.isProtectedDataAvailable {
  case true: break
  case false:
    NotificationCenter.default.addObserver(self,
                        selector: selector,
                        name: protectedDataAvailabilityNotificationName,
                        object: nil)
  }
}

@objc func protectedDataAvailableNotification(notification: NSNotification) {
  NotificationCenter.default.removeObserver(self, name: protectedDataAvailabilityNotificationName, object: nil)
  dataDidBecomeAvailable()
}

func dataDidBecomeAvailable() {
  refreshSubscriptionStatusSubscribers()
}

But it doesn't seem to work. The problem is that I cannot debug it, because the app has to enter background in order for this problem to manifest itself.

I have read several threads related to this issue here and on GitHub and it seems like there isn't any great solution. I am looking for some workarounds. Any hints are welcome. I will try the following now:

  1. Try to store that value in UserDefaults instead—it is not really a secret like a password/token, but I need to be sure it cannot be tampered with. Not sure if UserDefaults suffer from the same problem.
  2. Try to refactor to code to wrap the doesUserHavePremium and cache its return value in a property. That seems promising, because it never happens during fresh start thus I could always set that property on the app startup.
KeyChain returns nil for a value that is set
 
 
Q