We have been struggling with a sporadic issue in our iOS app for some time now, where it seems that occasionally our application will be launched and the keychain is not yet accessible. We have not found a way to reproduce this reliably.
As do many apps, we save some sensitive data (i.e., user credentials) to the keychain using kSecAttrAccessible = kSecAttrAccessibleWhenUnlocked. The app will read those values from the keychain during startup in the didFinishLaunchingWithOptions override of our app delegate. This works fine the large majority of the time.
But sometimes our users will report problems that indicate that the keychain values could not be read. If the user simply kills the app and restarts it, the values are still there and everything is working as normal. Our application does not run in the background, so I can't think of a case where it is started by anything other than a user action, which would mean the device is unlocked.
I am familiar with the applicationProtectedDataDidBecomeAvailable method, which is called by the OS when a device is unlocked and protected data like the keychain becomes accessible. I suppose we could check in didFinishLaunchingWithOptions if UIApplication.isProtectedDataAvailable is false, and if so defer the part of the app initialization that depends on the keychain to happen in the applicationProtectedDataDidBecomeAvailable method. I'm just always leery of coding a solution without being able to reproduce and test it.
Can anyone report that they have seen instances via app logs where the iOS protected data is not yet available in the didFinishLaunchingWithOptions method, but becomes available later?