Resolving: [_SwiftValue encodeWithCoder:]: unrecognized selector sent to instance
In a recent production app, I came across one of the most hard to track down iOS Crash bugs I have encountered. It took quite a bit of tracking down and there was nothing available online to help. Hopefully if anyone else out there hits this some day, this will save them some time.
The crash initially only happened on a certain client’s phone running iOS 11.4. None of our internal team was able to duplicate it. It happened several places, initially when launching our Intercom chat window for support and then also when showing the SFPasswordRemoteViewController to select a saved user name and password to login. Here is the stack trace from the safari login and the other instances are very similar.
-[_SwiftValue encodeWithCoder:]: unrecognized selector sent to instance 0x1d0257e80 Foundation +[NSKeyedArchiver archivedDataWithRootObject:] 7 UIKit _UIRecordArgumentOfInvocationAtIndex 8 UIKit -[_UIAppearanceRecorder _recordInvocation:withClassName:containerClassNames:traitCollection:selectorString:forRemoteProcess:] 9 UIKit __54+[_UIAppearance _recordersExcludingSource:withWindow:]_block_invoke 10 CoreFoundation -[__NSDictionaryM enumerateKeysAndObjectsWithOptions:usingBlock:] 11 UIKit +[_UIAppearance _recordersExcludingSource:withWindow:] 12 UIKit UIViewServiceCurrentAppearanceSerializedRepresentations 13 UIKit +[_UIRemoteViewController _requestViewController:traitCollection:fromServiceWithBundleIdentifier:service:connectionHandler:] 14 UIKit +[_UIRemoteViewController requestViewController:fromServiceWithBundleIdentifier:connectionHandler:] 15 SafariServices +[SFPasswordRemoteViewController requestViewControllerWithConnectionHandler:] 16 SafariServices -[_SFAppAutoFillPasswordViewController _connectToServiceWithCompletion:] 17 SafariServices -[_SFPasswordViewController _connectToService] 18 SafariServices -[_SFPasswordViewController init] 19 SafariServices -[_SFAppAutoFillPasswordViewController init] 20 UIKit -[UIKeyboardHiddenViewController presentAutofillVCWithAnimation:] 21 UIKit -[UIPresentationController transitionDidFinish:]
At first glance, this looks like a pure system bug. But, I am a believer that Apple would not let such a silly bug slip through their system and rather than put the blame on them, I figured it must be something conditions we were creating which was causing this to happen.
So, the Safari controller is using this internal RemoteViewController class which makes a call to Serialize the current appearance of the app and that causes the crash.
Serializing current appearance eh?? As I am regularly a good citizen of the UIView appearance proxy for setting default UI behaviors, I thought this could be to blame. When I commented out my appearance code, which runs from my App Delegate at launch I was excited to see that the crash no longer occurred!
I was then able to narrow the code down to a single line that caused the error to occur
//This is okay UITabBarItem.appearance().setTitleTextAttributes([kCTFontAttributeName as NSAttributedStringKey: UIFont.systemFont(ofSize: 9).bold()], for: .normal) //but, ut oh... don't do this one //UITabBarItem.appearance().setTitleTextAttributes([kCTFontAttributeName as NSAttributedStringKey: UIFont.systemFont(ofSize: 9).bold], for: .selected)
As I am typing this, I am just realizing that in the second line, I am passing in a method not the result of the method to the value of the default font. Ie, if you look closely you will see I forgot the parenthesis after the word bold. Note, bold() is an extension I added to UIFont to give me the bold version of a given font, nothing fancy.
So— there you go! If you get a crash like the one above, check your .appearance() proxy calls if you use them and make sure you don’t have any dumb-a$$ typos like I did and hopefully it won’t waste as much of your time as it has mine :-p