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?
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
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
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 */
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
}
}