1

I wish to create a class which will store a Date and any object that conforms to the Codable protocol. I would like this class to also conform to the Codable protocol itself.

I can do this for one object as follows:

class CodableContainerA: NSObject, Codable {
    var date: Date?
    var item: CodableTypeA?
}

I'd rather not have to create a separate CodableContainerX for each CodableTypeX I have.

My current workaround is to create a class called CodableBaseClass that conforms to Codable, derive every CodableType from it and define my class as follows:

class CodableContainer: NSObject, Codable {
    var date: Date?
    var item: CodableBaseClass?
}

This seems a long way around and feels like something I should be able to do by making the CodableTypes conform to a protocol, but I'm not sure how. If I define item to be of type Codable? or (Any & Codable)? I get an error stating

Type 'CodableContainer' does not conform to protocol 'Decodable'

I'm using Swift 4.

Any help or advice would be gratefully accepted. Many thanks,

0

2 Answers 2

5

This is what generic classes are for:

class CodableContainer<T: Codable>: NSObject, Codable {
    var date: Date?
    var item: T?
}
Sign up to request clarification or add additional context in comments.

Comments

4

Whenever you find yourself wondering about a separate class for each underlying type, think "generics". E.g.

struct CodableContainer<T: Codable>: Codable { 
    let date: Date
    let item: T
}
  • I'd use struct unless you needed class for some specific reason.
  • I'd make the properties immutable unless you needed them mutable for some reason.
  • I wouldn't subclass NSObject unless there was some specific reason that this particular container needed to be NSObject subclass.
  • I'd make the properties non-optional unless you absolutely needed them to be optional.

But edit this as you see fit. The key point is the generic pattern.


You might want a decoding function that decodes using some consistent DateDecodingStrategy, e.g.

extension CodableContainer {
    static func decodeJSON(_ data: Data) throws -> CodableContainer {
        let decoder = JSONDecoder()
        decoder.dateDecodingStrategy = .iso8601
        return try decoder.decode(self, from: data)
    }
}

Obviously, use whatever dateDecodingStrategy you want. But then you can decode with:

let result = try CodableContainer<Foo>.decodeJSON(data)

1 Comment

I've marked Code Different's answer as the accepted answer as it was first and more concise but I do really appreciate your answer and suggestions and I have incorporated them into my code. These are all things I've wondered about today but I figured I'd get it working before I made it work well. Hopefully my code is now both! Many thanks.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.