A quick update. I am still battling with this problem and the crashes are consistently showing only on iOS 9. With radically larger number of sessions, in hundreds of thousands daily on iOS 10+.
And since iOS 9 is considered dead by many it has become an academic effort of mine to figure this one out. With Apple dropping iOS 9 from Xcode probably next year, I still want to have a version in App Store that works great on these older devices.
I am having a hard time producing a reproducible test case, because the problem shows up absolutely randomly and appears to have something to do with how internals of Dictionary and Set behave on iOS 9. Code compiled with Xcode 12.2, latest available swift, swift runtime embedded in the app.
I was able to reduce intensity of the crashes drastically by prepending each Dictionary lookup with forced computation of hashValue, and although I can not explain why it would help, it seems to somewhat reduce the crashes.
Additionally, whenever I stop the debugger on failed precondition, and then examine the Dictionary, the value is always there, as if the debugger forced something to happen on the Dictionary after the process stopped.
Here is what I'm doing:
_ = key.hashValue
dict.forEach { k, _ in k.hashValue }
precondition(dict[key] != nil)
guard let x = dict[key] else {
	NSLog("dict[key] => \(String(describing: dict[key]))"
}
And I can still fail randomly and infrequently on line 4, or on line 5. If it fails on line 5, the NSLog prints the value successfully. So the second lookup always succeeds. Nonsense?
The `Equatable and Hashable` requirement was reduced to absolute minimum simply comparing/hashing one string value. The Dictionary is accessed via dispatchPrecondition checks from always the same non-main queue and is buttery smooth on iOS 10+ in production. Random iOS 9 madness :)
Topic:
Programming Languages
SubTopic:
Swift
Tags: