web-dev-qa-db-fra.com

Quelle est la différence entre facultatif et decodeIfPresent lors de l'utilisation de Decodable pour l'analyse JSON?

J'utilise le protocole Codable de Swift 4 première fois, je ne peux pas comprendre l'utilisation de decodeIfPresent de Decodable.

/// Decodes a value of the given type for the given key, if present.
///
/// This method returns `nil` if the container does not have a value associated with `key`, or if the value is null. The difference between these states can be distinguished with a `contains(_:)` call.
///
/// - parameter type: The type of value to decode.
/// - parameter key: The key that the decoded value is associated with.
/// - returns: A decoded value of the requested type, or `nil` if the `Decoder` does not have an entry associated with the given key, or if the value is a null value.
/// - throws: `DecodingError.typeMismatch` if the encountered encoded value is not convertible to the requested type.
public func decodeIfPresent(_ type: String.Type, forKey key: KeyedDecodingContainer.Key) throws -> String?

Ici, il suggère qu'il renvoie nil, si la valeur n'est pas présente avec la clé associée. Si c'est la seule raison, alors comment elle diffère de la propriété facultative, car la variable facultative est également définie sur nil si la valeur n'est pas présente en réponse.

21
technerd

Il y a une différence subtile mais importante entre ces deux lignes de code:

// Exhibit 1
foo = try container.decode(Int?.self, forKey: .foo)
// Exhibit 2
foo = try container.decodeIfPresent(Int.self, forKey: .foo)

La pièce 1 analysera:

{
  "foo": null,
  "bar": "something"
}

mais pas:

{
  "bar": "something"
}

tandis que la pièce 2 analysera avec plaisir les deux. Ainsi, dans les cas d'utilisation normaux des analyseurs JSON, vous aurez besoin de decodeIfPresent pour chaque option de votre modèle.

61
Gunter Hager

Oui, le commentaire de @ Sweeper a un sens.

Je vais essayer de l'expliquer selon ma compréhension.

public class User : Decodable{

    public var firstName:String
    public var lastName:String
    public var middleName:String?
    public var address:String
    public var contactNumber:String


    public enum UserResponseKeys: String, CodingKey{
        case firstName = "first_name"
        case lastName = "last_name"
        case middleName = "middle_name"
        case address = "address"
        case contactNumber = "contact_number"
    }

    public required init(from decoder: Decoder) throws {

        let container = try decoder.container(keyedBy: UserResponseKeys.self)

        self.firstName = try container.decode(String.self, forKey: .firstName)
        self.lastName = try container.decode(String.self, forKey: .lastName)
        self.middleName = try container.decodeIfPresent(String.self, forKey: .middleName)
        self.address = try container.decode(String.self, forKey: .address)
        self.contactNumber = try container.decode(String.self, forKey: .contactNumber)
    }

}

Ci-dessus se trouve ma classe User, dans laquelle j'ai marqué middleName comme paramètre facultatif, car il est possible que la réponse JSON ne fournisse pas la paire de valeurs-clés middleName en réponse, donc nous peut utiliser decodeIfPresent.

self.middleName = try container.decodeIfPresent(String.self, forKey: .middleName)

Alors que pour d'autres variables qui sont des champs obligatoires, nous sommes sûrs qu'il n'est pas nécessaire d'utiliser facultatif pour cela. Nous n'avons utilisé que decode pour cela car cette méthode ne retourne pas facultative.

public func decode(_ type: String.Type, forKey key: KeyedDecodingContainer.Key) throws -> String

Au-dessus de decode, la fonction renvoie String tandis que decodeIfPresent renvoie String?, afin que nous puissions utiliser une variable facultative pour stocker cela.

Donc, la conclusion finale est que si vous n'êtes pas sûr du contrat de réponse de service ou si vous pouvez traiter avec des services tiers où la réponse et les paramètres JSON peuvent changer à votre insu, vous pouvez utiliser decodeIfPresent pour qu'il puisse gérer l'absence de paramètre particulier dans la réponse et définir la valeur comme nil.

6
technerd