【问题标题】:How do I pre-process data after loading it from JSON in Swift?在 Swift 中从 JSON 加载数据后如何预处理数据?
【发布时间】:2021-01-08 23:07:54
【问题描述】:

假设我有一个包含这些数据的 JSON:

[ 
  { "id": "a",
    "x": 1,
    "y": 1  },

  { "id": "b",
    "x": 7,
    "y": 12 },
  .
  .
  .
  {etc.}
]

在 Swift 中,我可以将其加载到结构中:

struct jsonDataStruct: Codable, Identifiable {
    let id: String
    let x: Int
    let y: Int
}

但是,例如,如果我想计算 x 和 y 之间的距离怎么办?通常,我编写了一个带有初始化器的结构,如下所示:

struct coordinates: Identifiable {
    
    let id: String
    let x: Int
    let y: Int
    let length: Int?

    init(id: String, x: Int, y: Int) {
        self.x = x
        self.y = y
        self.distance = sqrt(x * x + y * y)

        // do other calculations or processing
    }
    
}

当我创建一个对象时:

let dudeWheresMyCar = coordinates(id: "my car", x: 12, y: 18)
print("it's \(dudeWheresMyCar.distance) meters away")

在创建坐标对象时自动计算距离。

我将如何使用上面的 struct jsonDataStruct 做到这一点?我已经为它编写了一个初始化程序,但是当从 JSON 加载数据时它似乎没有被调用:

Bundle-Decodable.swift:

import Foundation

extension Bundle {
    func decode(_ file: String) -> [jsonDataStruct] {
        guard let url = self.url(forResource: file, withExtension: nil) else {
            fatalError("Failed to locate \(file) in bundle.")
        }
        
        guard let data = try? Data(contentsOf: url) else {
            fatalError("Failed to load \(file) from bundle.")
        }
        
        let decoder = JSONDecoder()
        
        guard let loaded = try? decoder.decode([jsonDataStruct].self, from: data) else {
            fatalError("Failed to decode \(file) from bundle.")
        }
        
        return loaded
    }
}

ContentView.Swift:

import SwiftUI

struct ContentView: View {
    
    let testJsonData = Bundle.main.decode("testData.json")
    
    var body: some View {
        Text("\(testJsonData.count)")
            .padding()
    }
}

我可以在运行时根据需要简单地计算距离或任何其他值,但是预先计算它意味着它已经准备好使用,并且不必编写额外的代码。

我确信这个基本问题之前已经回答过,但作为一名业余编码员,我很可能会错过它,因为我可能不知道要查找什么或如何提出问题。

谢谢!

【问题讨论】:

  • 首先,属性distance(或length - 你都有)更好地表示为计算属性var distance: Double { sqrt(x * x + y * y) } - 这样你根本不需要解码它。或者,您需要编写自定义 init(from: Decoder) 并在那里计算 distance。此外,强烈建议遵循大写类型名称的 Swift 约定:struct JsonDataStruct { }struct Coordinates { }
  • 非常感谢您的建议!我还有很多东西要学

标签: json swift swiftui


【解决方案1】:

如果你真的想把它保留在初始化器中,你可以覆盖这个初始化器,它在解码过程中被调用:

init(from decoder: Decoder)

也就是说,为什么不把它作为结构本身的实例方法呢?没有理由需要在初始化时进行此计算。像这样的:

struct coordinates: Codable {
    let id: String
    let x: Int
    let y: Int
    let length: Int?

    func distance() -> Int {
        return sqrt(x * x + y * y)
    }
}

【讨论】:

  • 非常感谢!我考虑让它成为一个函数,但我希望做的是预先计算值,特别是如果它在运行时计算成本很高
  • 顺便说一句,初始化(来自解码器:解码器)帮助!它为我指明了正确的方向,我能够找到示例。谢谢!
【解决方案2】:

试试吧!这个

struct coordinates: Codable {
    let id: String?
    let x: Int?
    let y: Int?

    var distance:Int {
        let X = x ?? 0
        let Y = y ?? 0
        return Int(sqrt(Double(X * X + Y * Y)))
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-12-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-13
    • 2017-08-17
    • 1970-01-01
    相关资源
    最近更新 更多