Как вложить тип литья в Swift? - PullRequest
1 голос
/ 04 апреля 2020

У меня есть json объект, содержащий вложенные словари, которые я пытаюсь разобрать в swift:

{
    "ambientLightColor" : [100.0, 200.0, 300.0],

    "lights" : {
        "light1" : {"position" : [ 5, 5, 0], "direction" : [0,0,0], "color" : [0.0,0.7,0.3]},
        "light2" : {"position" : [-5, 5, 0], "direction" : [0,0,0], "color" : [0.8,0.2,0.1]},
        "light3" : {"position" : [ 0,-5, 0], "direction" : [0,0,0], "color" : [0.3,0.3,0.9]}
    }  
}

Поскольку объект root - это словарь с ключами в виде строк, я приведу его к такому для начала, как это сделано в примере здесь https://developer.apple.com/swift/blog/?id=37

 if let scene = sceneJSON as? [String: Any] {

    if let ambientRGB = scene["ambientLightColor"] as? [f1] {
        ambientLightColor = f3(ambientRGB[0],ambientRGB[1],ambientRGB[2])
    }

    if let lights = scene["lights"] as? [String: Any] {
        for (lightName, properties) in lights {
            let position = properties["position"]
            let direction = properties["direction"]
            let color = properties["color"]
            self.lights.append(Light(position: f3(position[0], position[1], position[2]), direction: f3(direction[0], direction[1], direction[2]), color: f3(color[0], color[1], color[2])))
        }
    }

}

Поскольку значения словаря root сначала приводятся как «Любые», они должны затем быть преобразованы в более Используемый тип при использовании записи. Это достаточно просто для первой записи, где я использую if let ... as? [f1] для приведения значения словаря [100.0, 200.0, 300.0] к массиву одиночных чисел с плавающей точкой перед их использованием для создания float3 (я не уверен, как напрямую приводить к float3 из массива чисел с плавающей запятой, но это не важно ).

Второй случай немного сложнее, поскольку он снова содержит другой вложенный словарь, хотя я не хочу использовать if для каждого отдельного элемента, скорее я хотел бы использовать a для l oop как показано выше. Теперь я знаю, что должен также преобразовать значение словаря свойств из любого типа в словарь в форме [String: [f1]].

Я попытался преобразовать его в первое преобразование словаря:

    if let lights = scene["lights"] as? [String: [String: [f1]] {
        for (lightName, properties) in lights {
            let position = properties["position"]
            let direction = properties["direction"]
            let color = properties["color"]
            self.lights.append(Light(position: f3(position[0], position[1], position[2]), direction: f3(direction[0], direction[1], direction[2]), color: f3(color[0], color[1], color[2])))
        }

Это дает мне ошибку из-за того, что [f1] является необязательным, и при запуске он также не находит json объектов, соответствующих этому типу.

Я также пытался

    if let lights = scene["lights"] as? [String: [String: Any] {
        for (lightName, properties) in lights {
            let position = properties["position"] as! [f1]
            let direction = properties["direction"] as! [f1]
            let color = properties["color"] as! [f1]
            self.lights.append(Light(position: f3(position[0], position[1], position[2]), direction: f3(direction[0], direction[1], direction[2]), color: f3(color[0], color[1], color[2])))
        }

Хотя это дает мне любую ошибку из-за того, что я не могу соединить NSNumber с плавающей точкой, что очень трудно исправить, когда они находятся в массиве.

Я также пытался

    if let lights = scene["lights"] as? [String: Any] {
        for case let (lightName, properties as? [String:[f1]]) in lights {
            let position = properties["position"]
            let direction = properties["direction"]
            let color = properties["color"]
            self.lights.append(Light(position: f3(position[0], position[1], position[2]), direction: f3(direction[0], direction[1], direction[2]), color: f3(color[0], color[1], color[2])))
        }

Кажется, что это был бы хороший способ написать решение, но swift не примет приведение типов в скобках из пары словарей.

Очень хотелось бы получить хороший краткий способ сделать это. Спасибо.

Ответы [ 2 ]

0 голосов
/ 05 апреля 2020

Этой записи в блоге 4 года. JSON Синтаксический анализ в Swift совершенно другой, так как был представлен Codable.

Предполагая, что f и f3 являются псевдонимами типов для Float и SIMD3<Float> соответственно, тогда вы можете просто использовать:

import Foundation
import simd
let json = """
{
    "ambientLightColor" : [100.0, 200.0, 300.0],

    "lights" : {
        "light1" : {"position" : [ 5, 5, 0], "direction" : [0,0,0], "color" : [0.0,0.7,0.3]},
        "light2" : {"position" : [-5, 5, 0], "direction" : [0,0,0], "color" : [0.8,0.2,0.1]},
        "light3" : {"position" : [ 0,-5, 0], "direction" : [0,0,0], "color" : [0.3,0.3,0.9]}
    }  
}
"""

struct Light: Codable {
    let position: SIMD3<Float>
    let direction: SIMD3<Float>
    let color: SIMD3<Float>
}

struct Scene: Codable {
    let ambientLightColor: SIMD3<Float>
    let lights: [String: Light]
}

let jsonData = json.data(using: .utf8)!
let scene = try! JSONDecoder().decode(Scene.self, from: jsonData)
print(scene)
0 голосов
/ 04 апреля 2020

Я полагаю, что проблему, с которой вы столкнулись, можно обойти, используя итерации ключей, вместо использования варианта for (key, value). Вот пища для размышлений. Кроме того, что касается проблемы NSNumber / Float, я обнаружил, что приведение как [Double] и сопоставление с [Float] работало нормально, где приведение как [Float] не удалось.

for key in lights.keys {
    let lightDict = lights[key] as! [String: Any]
    let position = lightDict["position"] as! [Double]
    let direction = lightDict["direction"] as! [Double]
    let color = lightDict["color"] as! [Double]

    print(position)
    print(direction)
    print(color)

    let floats = color.map { Float($0) }
    print(floats)
}
...