web-dev-qa-db-fra.com

extension du dictionnaire où <String, AnyObject>

J'essaie de créer une extension de dictionnaire où Dictionary est du type <String, AnyObject>.

Regardait dans de nombreux endroits et essayait différentes approches, mais aucune ne semblait fonctionner. C'était l'un d'entre eux:

extension Dictionary where <String, AnyObject>{
    var jsonString:String {
        return ""
    }
}

ne autre méthode qui n'a pas fonctionné pour une raison quelconque:

extension Dictionary where Key:Hashable, Value:AnyObject {

    var jsonString:String {

        do {
           let stringData = try NSJSONSerialization.dataWithJSONObject(self, options: NSJSONWritingOptions.PrettyPrinted)
            if let string = String(data: stringData, encoding: NSUTF8StringEncoding){
                return string
            }
        }catch _ {

        }
        return ""
    }
}

Got: le type d'argument 'Dictionary' n'est pas conforme au type attendu de 'AnyObject'

39

> = 3,1

A partir de la 3.1, nous pouvons faire des extensions concrètes, c'est-à-dire:

extension Dictionary where Key == String {}

<3,1

Nous ne pouvons pas conformer des types de béton avec des génériques de béton, c'est-à-dire:

extension Dictionary where Key == String

Cependant, comme Dictionary est conforme à la séquence et que nous pouvons conformer les types de protocoles avec des génériques concrets, nous pourrions faire:

extension Sequence where Iterator.Element == (key: String, value: AnyObject) {
    func doStuff() {...

Sinon, nous pouvons contraindre notre clé à un protocole dont la chaîne se conforme à ceci:

extension Dictionary where Key: StringLiteralConvertible, Value: AnyObject {
    var jsonString: String {
        return ""
    }
}

Selon votre réponse mise à jour. La sérialisation Json a besoin d'un objet, Swift Les dictionnaires sont des structures. Vous devez convertir en NSDictionary Vous devez spécifier Key pour vous conformer à NSObject pour convertir correctement en NSDictionary.

Petite remarque: les dictionnaires tapent déjà constrain Key pour être Hashable, donc votre contrainte d'origine n'ajoutait rien.

extension Dictionary where Key: NSObject, Value:AnyObject {

    var jsonString:String {

        do {
            let stringData = try NSJSONSerialization.dataWithJSONObject(self as NSDictionary, options: NSJSONWritingOptions.PrettyPrinted)
            if let string = String(data: stringData, encoding: NSUTF8StringEncoding){
                return string
            }
        }catch _ {

        }
        return ""
    }
}

Notez que les dictionnaires doivent être conformes à ce type pour accéder à l'extension.

let dict = ["k" : "v"]

Deviendra le type [String : String], vous devez donc être explicite en déclarant:

let dict: [NSObject : AnyObject] = ["k" : "v"]
87
Logan

Approche Swift

extension Dictionary where Key: ExpressibleByStringLiteral, Value: AnyObject

Comme StringLiteralConvertible est désormais obsolète et remplacé par ExpressibleByStringLiteral

6
Aidan Malone

Ajout à la réponse fournie par @Logan, pour ceux qui cherchent à ajouter des propriétés personnalisées à la chaîne de caractères Dictionary, cela est également possible (cherchait à le faire lorsque je suis tombé sur ce SO question):

extension Dictionary where Key: StringLiteralConvertible {

    var somePropertyThatIsAColor:UIColor? {
        get {
            return self["someKey"] as? UIColor
        }
        set {
            // Have to cast as optional Value
            self["someKey"] = (newValue as? Value)
    }

}
4
Jason Henderson

Mise à jour pour Swift
Voici mon exemple utilisant ExpressibleByStringLiteral pour Key et Any pour Value.

extension Dictionary where Key: StringLiteralConvertible, Value: Any {
    var jsonString: String? {
        if let dict = (self as AnyObject) as? Dictionary<String, AnyObject> {
            do {
                let data = try JSONSerialization.data(withJSONObject: dict, options: JSONSerialization.WritingOptions(rawValue: UInt.allZeros))
                if let string = String(data: data, encoding: String.Encoding.utf8) {
                    return string
                }
            } catch {
                print(error)
            }
        }
        return nil
    }
}

puis je l'utilise comme ceci:

let dict: Dictionary<String, AnyObject> = [...]
let jsonString = dict.jsonString

Vous pouvez vous convertir en AnyObject ou NSObject, les deux fonctionnent, puis vous décompressez en tant que dictionnaire ou tout autre type spécifique.

3
Jonauz

Ainsi, Dictionary est:

public struct Dictionary<Key : Hashable, Value> : CollectionType, DictionaryLiteralConvertible {..}

Que diriez-vous d'une extension de protocole? :RÉ

extension CollectionType where Self: DictionaryLiteralConvertible, Self.Key == String, Self.Value == AnyObject, Generator.Element == (Self.Key, Self.Value) {
...
}
2
Andrei Popa

Je n'ai pas réussi à faire fonctionner l'une des solutions proposées dans Swift 3, mais en profitant du pont entre Dictionary et NSDictionary, je pouvais faire ce travail:

extension NSDictionary {

    var jsonString:String {

        do {
            let stringData = try JSONSerialization.data(withJSONObject: self, options: .prettyPrinted)
            if let string = String(data: stringData, encoding: .utf8) {
                return string
            }
        }catch _ {

        }
        return ""
    }
}
1
Drew C

Toute personne utilisant [String:Any] au lieu de Dictionary peut utiliser l'extension ci-dessous

extension Dictionary where Key == String, Value == Any {

    mutating func append(anotherDict:[String:Any]) {
        for (key, value) in anotherDict {
            self.updateValue(value, forKey: key)
        }
    }
}
0
Dhaval H. Nena