2016-03-28 1 views
3

Je suis en train de représenter une structure JSON dans rapide pour une utilisation avec EVReflection. La chaîne ressemble à ceci:Comment représenter les types de tableaux imbriqués pour EVReflection

{ 
    "date": 2457389.3333330001, 
    "results": 
     { 
      "sun": [[559285.95145709824, 202871.33591198301, 61656.198554897906], [127.6163120820332, 948.44727756795123, 406.68471093096883]], 
      ... etc ... 
      "geomoon": [[-401458.60657087743, -43744.769596474769, -11058.709613333322], [8433.3114508170656, -78837.790870237863, -26279.67592282737]] 
     }, 
    "unit": "km" 
} 

J'ai essayé plusieurs approches pour modéliser les « résultats » interne du dictionnaire, qui est calée avec une chaîne et a toujours des valeurs qui sont un ensemble de deux éléments, dont chacun ont trois doubles (c.-à-d., [String: [[Double]]] est un modèle que j'ai essayé). Peu importe ce que je fais, je reçois une erreur le long de ces lignes:

ERROR: valueForAny unkown type , type _NativeDictionaryStorage<String, Array<Array<Double>>>. Could not happen unless there will be a new type in Swift.

Quelqu'un at-il une idée comment modéliser ce si EVReflection est heureux? J'ai aussi eu le sentiment de l'expression Could not happen unless there will be a new type in Swift qu'il existe une autre méthode ou une modélisation différente avec des sous-types explicites que je peux ajouter qui lui donnerait ce dont elle a besoin, mais je ne peux pas expliquer ce qu'il faut faire des docs.

Répondre

1

Swift un Double est un struct. Faire des réflexions avec des structures a certaines limites. Je préfère utiliser NSNumber à la place.

Ma première pensée serait un modèle d'objet comme celui-ci:

class MyObject: EVObject { 
    var date: NSNumber? 
    var results: Result? 
    var unit: String? 
} 

class Result: EVObject { 
    var sun: [[NSNumber]]? 
    var geomoon: [[NSNumber]]? 
} 

Mais votre objet a une valeur imbriquée. Jusqu'à présent, je n'ai jamais testé EVReflection avec une structure comme celle-ci. Je vais essayer d'ajouter un test unitaire pour cela dans un instant. Il aurait été plus facile si le tableau intérieur était un objet

Mise à jour (quelque chose comme un objet avec une valeur x, y et z?): Cela semble fonctionner. Je l'ai testé cela avec les éléments suivants UnitTest:

func testNestedArry() { 
    let json = "{\"date\": 2457389.3333330001,\"results\": { \"sun\": [[559285.95145709824, 202871.33591198301, 61656.198554897906], [127.6163120820332, 948.44727756795123, 406.68471093096883]], \"geomoon\": [[-401458.60657087743, -43744.769596474769, -11058.709613333322], [8433.3114508170656, -78837.790870237863, -26279.67592282737]] }, \"unit\": \"km\" }" 
    let myObject = MyObject(json: json) 
    print(myObject.toJsonString()) 
} 

Et la sortie de myObject était:

{ 
    "date" : 2457389.333333, 
    "results" : { 
    "sun" : [ 
     [ 
     559285.9514570982, 
     202871.335911983, 
     61656.19855489791 
     ], 
     [ 
     127.6163120820332, 
     948.4472775679512, 
     406.6847109309688 
     ] 
], 
    "geomoon" : [ 
     [ 
     -401458.6065708774, 
     -43744.76959647477, 
     -11058.70961333332 
     ], 
     [ 
     8433.311450817066, 
     -78837.79087023786, 
     -26279.67592282737 
     ] 
    ] 
    }, 
    "unit" : "km" 
} 

Mise à jour 2: Comme indiqué ci-dessous 'clés' de la planète ne sont pas un ensemble fixe. Donc, en fait, cela devrait être traité comme un dictionnaire. Pour faire quelque chose comme ça, vous pouvez utiliser un 'hack' en utilisant setValue forKey pour remplir un dictionnaire. Pour faire cela, vous auriez besoin d'un modèle de données comme ceci:

class MyObject: EVObject { 
    var date: NSNumber? 
    var results: Result? 
    var unit: String? 
} 

class Result: EVObject { 
    var planets = [String: [[NSNumber]]]() 

    // This way we can solve that the JSON has arbitrary keys 
    internal override func setValue(value: AnyObject!, forUndefinedKey key: String) { 
     if let a = value as? [[NSNumber]] { 
      planets[key] = a 
      return 
     } 
     NSLog("---> setValue for key '\(key)' should be handled.") 
    } 
} 

Vous ne devez savoir que si vous voulez créer JSON pour cela, que vous aurez un niveau supplémentaire dans la hiérarchie des planètes. Si vous ne le souhaitez pas, une solution de contournement est possible en modifiant la propriété results en String: [[NSNumber]] Vous devrez également implémenter EVCustomDictionaryConverter. Voir les tests d'unité de contournement pour voir comment cela fonctionnerait.

+0

Malheureusement, les touches précises qui seront retournés dans « résultats » sont variables, et donc je ne peux pas construire une structure de résultats imbriqué comme vous le suggérez - je besoin que d'être un ensemble indéfini de [chaîne: [[valeur ]] éléments du dictionnaire. Mon seul espoir est-il de les lister tous comme optionnels? – Feldur

+0

Je pense que vous pouvez résoudre ce avec le truc que je l'ai fait ici: https://github.com/evermeer/EVWordPressAPI/blob/master/EVWordPressAPI/EVWordpressData.swift#L332 Utilisez le forUndefinedKey setValue afin que vous serez en mesure de capturer toutes les 'propriétés' sans qu'elles soient une propriété réelle, puis définissez les données dans un dictionnaire local. Je vais le faire pour vous plus tard ... –

+0

Prometteur. Ensuite, je m'attends à ce que vous me disiez que vous avez tout ce qui fonctionne par l'intermédiaire d'un terrain de jeu et que je (qui ne peut pas faire fonctionner les importations) vous saluera! – Feldur