I would advise against subclass approach. Subclasses are best suited when extending a class with new behaviors, not when changing its behaviors.
There are a couple of approaches I would consider.
One is to just have a convenience initializer that takes the date decoding strategy:
extension JSONDecoder {
/// Return new `JSONDecoder` with particular date decoding strategy
convenience init(dateDecodingStrategy: JSONDecoder.DateDecodingStrategy) {
self.init()
self.dateDecodingStrategy = dateDecodingStrategy
}
}
Then you can do things like:
URLSession.shared.dataTaskPublisher(for: request)
.receive(on: DispatchQueue.main)
.tryMap(handleHTTPOutput)
.decode(type: [TaskModel].self, decoder: JSONDecoder(dateDecodingStrategy: .iso8601))
Another approach is to create your own factory method with the appropriate date decoding strategy:
extension TopLevelDecoder where Self == JSONDecoder {
/// Return new `JSONDecoder` with `.iso8601` date decoding strategy
static func jsonWithIso8601() -> JSONDecoder {
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .iso8601
return decoder
}
}
Then you can do things like:
URLSession.shared.dataTaskPublisher(for: request)
.receive(on: DispatchQueue.main)
.tryMap(handleHTTPOutput)
.decode(type: [TaskModel].self, decoder: .jsonWithIso8601())
I generally have multiple properties I have to set up for my encoders/decoders, so I personally have a private
(or internal
) factory for decoders for my particular web service:
private extension TopLevelDecoder where Self == JSONDecoder {
/// Return new `JSONDecoder` designed for the “Foobar” web service
static func forFoobar() -> JSONDecoder {
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .iso8601
decoder.keyDecodingStrategy = .convertFromSnakeCase
…
return decoder
}
}
Then you can do things like:
URLSession.shared.dataTaskPublisher(for: request)
.receive(on: DispatchQueue.main)
.tryMap(handleHTTPOutput)
.decode(type: [TaskModel].self, decoder: .forFoobar())
There are lots of variations on the theme, but hopefully this illustrates a few basic ideas.
But, as a general design principle, I would generally advise against a static
property given that this is a reference type with its own mutable properties. You might be careful to not mutate it right now, but it is the sort of thing that bites you a year or two later when accidentally mutate one of the properties, unaware of the unintended consequences that sharing introduced.
Regarding your error trying to set DateDecodingStrategy
, that is not a property. It is an enum
(for example, as used as a parameter type in the convenience initializer of my first example, above).
It would be analogous to:
enum Answer {
case yes
case no
}
var answer: Answer = .yes // fine
answer = .no // fine
Answer = .no // ERROR: this makes no sense; `Answer` is a type, an `enum`, not a property or variable