web-dev-qa-db-fra.com

Parcourez la structure Swift pour obtenir les clés et les valeurs

Je voudrais faire une boucle sur chaque clé de mystruct et imprimer son clé et sa valeur pour chaque propriété.

struct mystruct {
  var a = "11215"
  var b = "21212"
  var c = "39932"
}

func loopthrough {
    for (key, value) in mystruct {
        print("key: \(key), value: \(value)") // Type mystruct.Type does not conform to protocol 'Sequence'
    }
}

Mais en utilisant les quelques lignes ci-dessus, je reçois toujours ce message d'erreur: 

Type mystruct.Type n'est pas conforme au protocole 'Séquence'

Comment puis-je éviter de recevoir ce message?

4
user9225354

Tout d’abord, utilisons CamelCase pour le nom de la structure

struct MyStruct {
    var a = "11215"
    var b = "21212"
    var c = "39932"
}

Ensuite, nous devons créer une valeur de type MyStruct

let Elm = MyStruct()

Nous pouvons maintenant construire une valeur Mirror basée sur la valeur Elm.

let mirror = Mirror(reflecting: Elm)

La valeur Mirror nous permet d'accéder à toutes les propriétés de Elm, voici comment

for child in mirror.children  {
    print("key: \(child.label), value: \(child.value)")
}

Résultat:

clé: facultatif ("a"), valeur: 11215

clé: facultatif ("b"), valeur: 21212

clé: facultatif ("c"), valeur: 39932

15
Luca Angeletti

utilisez le code suivant pour obtenir un tableau de toutes les propriétés 

protocol PropertyLoopable
{
    func allProperties() throws -> [String]
}

extension PropertyLoopable {
    func allProperties() throws -> [String] {

        var result: [String] = []

        let mirror = Mirror(reflecting: self)

        // Optional check to make sure we're iterating over a struct or class
        guard let style = mirror.displayStyle, style == .struct || style == .class else {
            throw NSError()
        }

        for (property,_) in mirror.children {
            guard let property = property else {
                continue
            }
            result.append(property)
         //   result[property] = value
        }

        return result
    }
}

Maintenant juste

let allKeys = try  self.allProperties()

N'oubliez pas d'appliquer le protocole 

J'espère que c'est utile 

2
Prashant Tukadiya

Vous pouvez utiliser l'introspection à l'exécution (sur une instance de votre type) combinée à une correspondance de modèle de liaison de valeur pour extraire les noms et les valeurs de propriétés. ce dernier utilisait pour décompresser la propriété optionnelle label de l'occurrence Mirror utilisée pour représenter la sous-structure de votre instance spécifique.

Par exemple.:

struct MyStruct {
    let a = "11215"
    let b = "21212"
    let c = "39932"
}

// Runtime introspection on an _instance_ of MyStruct
let m = MyStruct()
for case let (label?, value) in Mirror(reflecting: m)
    .children.map({ ($0.label, $0.value) }) {
    print("label: \(label), value: \(value)")
} /* label: a, value: 11215
     label: b, value: 21212
     label: c, value: 39932 */
2
dfri

J'espère que cela aidera encore quelqu'un: Ceci est ma version du protocole pour les classes/structures plus complexes (Objets dans Objets dans Objets ;-)) Je suis sûr qu'il existe une solution fonctionnelle plus élégante. mais c'était une solution rapide et sale, car je n'avais besoin que d'une solution temporaire pour la journalisation. 

protocol PropertyLoopable {
func allProperties() -> [String: Any]
}


extension PropertyLoopable {
func allProperties() -> [String: Any] {

    var result: [String: Any] = [:]
    let mirror = Mirror(reflecting: self)

    // make sure we're iterating over a struct or class
    guard let style = mirror.displayStyle, style == .struct || style == .class else {
        print("ERROR: NOT A CLASS OR STRUCT")
        return result
    }

    for (property, value) in mirror.children {
        guard let property = property else {
            continue
        }
        // It was a very complicated struct from a JSON with a 4 level deep structure. This is dirty dancing, remove unnecessary "for" loops for simpler structs/classes
        // if value from property is not directly a String, we need to keep iterating one level deeper
        if value is String {
            result.updateValue(value, forKey: property)
        } else {
            let mirror = Mirror(reflecting: value)

            for (property, value) in mirror.children {
                guard let property = property else {
                    continue
                }
                //let's go for a second level
                if value is String {
                    result.updateValue(value, forKey: property)
                } else {
                    let mirror = Mirror(reflecting: value)

                    for (property, value) in mirror.children {
                        guard let property = property else {
                            continue
                        }
                        //3rd level
                        if value is String {
                            result.updateValue(value, forKey: property)
                        } else {
                            let mirror = Mirror(reflecting: value)

                            for (property, value) in mirror.children {
                                guard let property = property else {
                                    continue
                                }
                                result.updateValue(value, forKey: property)
                            }
                        }
                    }
                }
            }
        }
    }
    return result
}

}

0
Santi Pérez