如何为EVReflection表示嵌套数组类型

时间:2016-03-28 23:40:59

标签: arrays swift json-deserialization

我正在尝试在swift中表示一个JSON结构,以便与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"
}

我尝试了几种方法对内部“结果”字典进行建模,该字典用字符串键入,并且始终具有两个元素的数组值,每个元素都有三个双精度数(即[String: [[Double]]]是我尝试过的一种模式。无论我做什么,我都会犯这样的错误:

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

有没有人知道如何对此进行建模,以便EVReflection很开心?我也从短语Could not happen unless there will be a new type in Swift中感觉到有另一种方法或不同的建模与我可以添加的显式子类型,它可以提供它所需要的东西,但我无法解释从文档中做什么。

1 个答案:

答案 0 :(得分:1)

在Swift中,Double是一个结构。使用结构进行反射有一些限制。我更喜欢使用NSNumber。

我的第一个想法是这样的对象模型:

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

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

但是你的对象有一个嵌套值。到目前为止,我从来没有用这样的结构测试EVReflection。我稍后会尝试为此添加一个单元测试。如果内部数组是一个对象(类似于具有x,y和z值的对象​​?),那会更容易。

<强>更新 这似乎有效。我用以下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())
}

myObject的输出是:

{
  "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"
}

更新2: 如下所述,行星'键'不是固定的集合。所以实际上这应该作为字典来处理。要做这样的事情,你可以使用setValue forKey填充字典来使用'hack'。为此,您需要一个这样的数据模型:

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.")
    }
}

你必须要知道,如果你想为此创建json,你将在行星的层次结构中有一个额外的等级。如果您不想这样,那么可以通过将results属性更改为String来实现一种解决方法:[[NSNumber]]然后您还需要实现EVCustomDictionaryConverter。请参阅变通方法单元测试以了解其工作原理。