【问题标题】:SwiftUI search field from a local JSON file来自本地 JSON 文件的 SwiftUI 搜索字段
【发布时间】:2020-01-28 17:00:04
【问题描述】:

我正在尝试从本地 JSON 文件中检索数据,如下所示:

[{
   "name": "John",
   "lastname": "Doe",
   "age": "30"
}, 
{
   "name": "Jane",
   "lastname": "Doe",
   "age": "20"
}
, 
{
   "name": "Baby",
   "lastname": "Doe",
   "age": "3"
}]

使用数据选择器的用户可以选择姓名和/或姓氏

import SwiftUI

struct ContentView : View {

    var names = ["John", "Jane", "Baby"]
    var lastnames = ["Doe", "Boe"]

    @State private var selectedNameItem = 0
    @State private var selectedLastNameItem = 0

    var body: some View {
       VStack {

          Picker(selection: $selectedNameItem, label: Text("Names:")) {
             ForEach(0 ..< names.count) {
               Text(self.names[$0]).tag($0)
             }
          }
          Text("Your choice: ")
           + Text("\(names[selectedNameItem])")
       }

       VStack {            
          Picker(selection: $selectedLastNameItem, label: Text("LastName:")) {
             ForEach(0 ..< lastnames.count) {
               Text(self.lastnames[$0]).tag($0)
             }
          }
          Text("Your choice: ")
           + Text("\(lastnames[selectedLastNameItem])")
       }

    }
}

一旦选择了姓名/姓氏(作为参数),我想显示一个文本,例如:“John Doe is 30 岁”

如何从 JSON 中读取数据并准确返回所选用户的年龄而不列出所有元素?

非常感谢, 法布里奇奥

【问题讨论】:

    标签: json swiftui swift5


    【解决方案1】:

    首先,我建议创建一个结构来表示您的 JSON 结构。请尝试以下操作:

    struct Person: Codable, Hashable {
        let name: String
        let lastname: String
        let age: String
    }
    
    typealias People = [Person]
    

    我通常创建一个typealias 来处理我的数据的数组版本。一旦你定义了你的数据结构来匹配你的 JSON,我通常会扩展我的数据以使从 JSON 加载变得容易。

    extension Person {
        static func load(fromJson json: URL) -> People {
            guard let data = try? Data(contentsOf: json) else {
                preconditionFailure("Unable to read data from URL")
            }
            let jsonDecoder = JSONDecoder()
            var people = People()
            do {
                people = try jsonDecoder.decode(People.self, from: data)
            } catch {
                print(error)
            }
            return people
        }
    }
    

    有更通用的方法来支持更广泛的模型,但对于您的示例来说,这既快速又简单。

    现在您已经有了使用模型的简单方法,可以通过像这样扩展 Array 类型来轻松解决您的想法:

    extension Array where Element == Person {
        func retrievePeople(byName name: String) -> People {
            return self.filter { $0.name == name }
        }
    
        func retrievePeople(byLastName lastname: String) -> People {
            return self.filter { $0.lastname == lastname }
        }
    
        func retrievePeople(byAge age: String) -> People {
            return self.filter { $0.age == age }
        }
    }
    

    这将允许您通过任何元素查询整个对象范围,然后返回匹配数组。如果您确定只有一个返回值,您可以使用以下代码获取第一个元素:

    // Let's assume your array of people is stored in this variable
    var myPeople: People
    if let person = myPeople.retrievePeople(byName: "John").first {
       // Do the things you want with this person object here
    }
    
    

    这种加载/处理数据的方式的好处是它易于快速生成,并且支持返回 0 个对象、1 个对象和多个对象。这也将允许您移动模型以使用 SwiftUI/Combine 的功能(这看起来就像您希望在上面做的那样)。

    【讨论】:

    • 感谢约翰的帮助!我会继续努力学习Swift和更深的Combine。
    猜你喜欢
    • 2023-01-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-14
    • 1970-01-01
    • 1970-01-01
    • 2021-11-16
    相关资源
    最近更新 更多