Reputation: 304
import Foundation
enum Errors: Error {
case badParse
}
public typealias JSONDictionary = [String: Any]
public func decode(_ dictionary: JSONDictionary, key: String) throws -> URL {
guard let string = dictionary[key] as? String else {
throw Errors.badParse
}
if let url = URL(string: string) {
return url
}
throw Errors.badParse
}
public func decode<T>(_ dictionary: JSONDictionary, key: String) throws -> T {
guard let value = dictionary[key] else {
throw Errors.badParse
}
guard let attribute = value as? T else {
throw Errors.badParse
}
return attribute
}
let url: URL = try decode(["url":"test/url"], key: "url") // url: test/url
let urlOptional: URL? = try? decode(["url":"test/url"], key: "url") // nil
The above code works as long as you're decoding a NON-optional. The specific non-generic decode function is called and the URL is constructed.
However, if you have an optionally type variable and decode it, it will not use the correct function. In swift 4.2, both optionals and non optionals would use the correct non-generic function, but since I updated to Xcode 11 swift 5.1, this behavior has been seen.
Any help would be greatly appreciated!
I would prefer not to make function signatures with optional returns such as
public func decode(_ dictionary: JSONDictionary, key: String) throws -> URL? {
because it is not scalable...and it used to work without it.
Upvotes: 1
Views: 46
Reputation: 272845
Evidently, how type inference works changed a little bit in Swift 5. If you just want it to use the correct overload, you just need to give it a little push:
let urlOptional: URL? = try? decode(["url":"test/url"], key: "url") as URL
by adding as URL
at the end.
Upvotes: 1