Debugging a subtle Swift bug that will make you facepalm
source link: https://www.jessesquires.com/blog/2018/11/07/debugging-subtle-swift-bug-facepalm/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
07 Nov 2018
software-dev debugging, ios, swift, xcode
The other day I was debugging a crash in a UI test for an open pull request at work. The bug turned out to be extremely subtle and difficult to notice. I spent way too much time staring at the changes, trying to understand what was wrong. Let’s see if you can spot the error.
Here’s the problematic line:
func toDictionary() -> [String: Any] {
var dict: [String: Any] = [:]
// code setting other keys and values...
dict[JSONKeys.dateClosed] = self.dateClosed?.toMongoDate
return dict
}
The details here don’t matter. This is some legacy JSON serialization code, predating the introduction of Codable
(SE-0166 and SE-0167). This function serializes the object to a JSON dictionary, self.dateClosed
is a Date
type, and JSONKeys.dateClosed
is a String
constant.
But what’s the bug? Let’s look at the definition of toMongoDate
(also some legacy code).
extension Date {
func toMongoDate() -> [String: Any] {
// return date in expected mongo date format
}
}
Seems fine, right? Everything compiles. There’s no issue with putting a [String: Any]
dictionary as the value in another [String: Any]
dictionary. Any
can be any type. But that’s what the problem turned out to be.
Let’s look at that line again: self.dateClosed?.toMongoDate
. This returns the function toMongoDate
. That is, the reference type () -> [String: Any]
— not the result of calling the function. I forgot the parentheses ()
. That line should read self.dateClosed?.toMongoDate()
. However, this worked and the compiler did not complain because functions are first class types, and setting a function as the value of a [String: Any]
dictionary is valid. This is clearly an argument for adopting Codable
, which would have prevented this mistake.
What’s worse: this exact error has happened in our code base in at least one other scenario. It’s so easy to overlook.
Much faceplam.
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK