0

I have a service that returns an array of objects in this form:

{
    result: [
        {
            objectId: "id",
            type: "objectType",
            content: { ... }
        }, ...
    ]
}

The content depends on the object type. I've tried building up a custom decoder this way (ContentItem is a protocol for ClassA, B and so on):

struct ContentDataItem: Decodable {
    var objectId: String?
    var type: String?
    var content: ContentItem?
    private enum CodingKeys: String, CodingKey {
        case objectId
        case type
        case content
    }

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        objectId = try container.decode(String.self, forKey: .objectId)
        type = try container.decode(String.self, forKey: .type)
        if let type = type {
            switch type {
            case "typeA":
                content = try container.decode(ClassA.self, forKey: .content)
            case "typeB":
                content = try container.decode(ClassB.self, forKey: .content)
                ...
            }
        }
    }
}

This works, but I get a high cyclomatic complexity (I'm aiming for sub-10, but I have 14 different classes for content). So I've tried changing my approach, making ContentItem the superclass and changing the init into something like this:

init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        objectId = try container.decode(String.self, forKey: .objectId)
        let type = try container.decode(String.self, forKey: .type)
        let itemTypes: [String: ContentItem.Type] = [
            "typeA": ClassA.self,
            "typeB": ClassB.self,
            ...
        ]
        guard let type = type, let contentItemType = itemTypes[type] else { return }
        content = try container.decode(contentItemType, forKey: .content)
    }

This reduces the cyclomatic complexity as I wanted, but it doesn't work anymore because the decode only returns objects of type ContentItem (the superclass), not the specific ClassA, ClassB that I want. Is there a way to make this approach work? What is wrong with it?

And more importantly, is there a more efficient way to parse this object?

Kappei
  • 714
  • 2
  • 15
  • 34

0 Answers0