web-dev-qa-db-fra.com

swift - puis-je appeler un init par défaut struct par membre à partir de ma méthode d'initialisation personnalisée?

Si je crée une structure Swift sans init, alors je peux appeler l'initialiseur membre par défaut généré par le compilateur, comme ceci:

struct OrderFill {
    let price:Int
    let qty: Int
    let timeStamp: NSDate
}
let o = OrderFill(price: 2, qty: 1, timeStamp: someDate)

Ce que j'aimerais faire, c'est créer une méthode d'init pratique pour désérialiser à partir d'un dictionnaire, qui enchaîne ensuite l'init par défaut par membre. Quelque chose comme

struct OrderFill {
    let price:Int
    let qty: Int
    let timeStamp: NSDate

    init(dict:[String:AnyObject]) throws {
        self.init(
            price: dict["price"] as! Int
            qty: dict["qty"] as! Int
            timeStamp: try parseDate(dict["ts"] as! String)
    }
}
let o = OrderFill(someDict)

Quand j'essaie d'écrire ce code, le compilateur (Xcode 7.2) me donne l'erreur "Argument supplémentaire 'qty' dans l'appel" comme s'il ne voyait pas le membre par défaut et essayait d'appeler récursivement init(dictionary)

Je peux écrire mon propre init membre par membre, ou je peux simplement assigner les propriétés directement à partir de ma init(dictionary), mais ce serait bien si je pouvais enchaîner l'appel. Y a-t-il un moyen de le faire rapidement?

32
Orion Edwards

Ajoutez votre propre initialiseur comme extension à votre structure. Les extensions ne peuvent pas supprimer les fonctionnalités existantes, elles conserveront donc l'initialiseur par défaut de struct.

struct OrderFill {
    let price: Int
    let qty: Int
    let timeStamp: NSDate
}

extension OrderFill {

    init(dict: [String: AnyObject]) throws {
        self.init(
            price: dict["price"] as! Int,
            qty: dict["qty"] as! Int,
            timeStamp: try parseDate(dict["ts"] as! String)
        )
    }
}

let o = OrderFill(someDict)
79
Sebastian Osiński

De les documents Apple sur l'initialisation :

Les types de structure reçoivent automatiquement un initialiseur membre par membre s'ils ne définissent aucun de leurs propres initialiseurs personnalisés

et

Notez que si vous définissez un initialiseur personnalisé pour un type de valeur, vous n'aurez plus accès à l'initialiseur par défaut (ou à l'initialiseur membre, s'il s'agit d'une structure) pour ce type. Cette contrainte empêche une situation dans laquelle une configuration essentielle supplémentaire fournie dans un initialiseur plus complexe est contournée par quelqu'un qui utilise accidentellement l'un des initialiseurs automatiques à la place.

Par conséquent, la réponse est [~ # ~] non [~ # ~] . Vous ne pouvez pas fournir un initialiseur personnalisé et utiliser l'initialiseur membre par membre en même temps.

Cela ressemble à this Swift evolution proposition parle d'étendre les capacités de l'initialiseur membre actuel. Mais bien sûr, cela n'est pas encore sorti, vous pouvez cependant toujours jeter un œil pour en savoir un peu plus sur les limites de la situation actuelle.

9
luk2302