Search code examples
iosswiftcodabledecodable

Set capacity to array of model in Decodable protocol


I want to set a model array max capacity if the user has not logged in even JSON response contains more records.

public class AlertsInbox: Codable {
    public var messages: [Messages]?
    public init(messages: [Messages]) {
        self.messages = messages
        if !GlobalVar.isLoggedIn,
            let capacity = GlobalVar.messageCapacity {
            self.messages?.reserveCapacity(capacity)
        }
    }
}

Decode json response:

let responseMessage = try JSONDecoder().decode(AlertsInbox.self, from: data)

Using reserveCapacity in init of model but it gets overridden with the number of records received in response.

How to restrict while decoding?

Thanks


Solution

  • You should not conditionally strip/drop out elements from an array in the Type's initializer. This consideration is against the responsibility role of Model object. Instead it's a job for the controller object.

    But you can have an access point in the model type. Let's say, you have a property messages in your AlertsInbox object. You can have another access point with another property, let's say, limitedMessages that will be a computed property.

    Look at the below code. I intentionally changed the type's semantics from Class to Struct. But you are free to use as your need.

    struct AlertsInbox: Codable {
        let messages: [Message]
    
        var limitedMessages: [Message] {
            // here you will use the value of your limit
            // if the limit exceeds the size of the array, whole array will be returned
            return Array(messages.prefix(5))
        }
    
        struct Message: Codable {
            let title: String
        }
    }
    

    Now you will use this, just like any other property, when you need the stripped out version of your actual messages. Like alertInbox.limitedMessages instead of the messages property.


    But if you are not satisfied with the above and wanna stick to your plan, you can do that as well. See:

    struct AlertsInbox: Codable {
        let messages: [Message]
    
        init(from decoder: Decoder) throws {
            let container = try decoder.container(keyedBy: CodingKeys.self)
            let messages = try container.decode([Message].self, forKey: .messages)
            // the idea of limiting the element numbers is same as the above
            self.messages = Array(messages.prefix(5))
        }
    
        struct Message: Codable {
            let title: String
        }
    }