Поле поиска SwiftUI из локального файла JSON - PullRequest
0 голосов
/ 28 января 2020

Я пытаюсь получить данные из локального 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])")
       }

    }
}

После выбора имени / фамилии (в качестве параметра) я хочу показать текст, например, такой: «Джону Доу 30 лет»

Как я могу читать данные из JSON и вернуть ровно возраст выбранного пользователем без списка всех элементов?

Большое спасибо, Фабрицио

1 Ответ

0 голосов
/ 28 января 2020

Для начала я рекомендую создать структуру, которая будет представлять вашу 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
    }
}

Есть более универсальные c способы сделать это для поддержки более широкий ряд моделей, но для вашего примера это быстро и просто.

Теперь, когда у вас есть простой способ работы с вашей моделью, простое решение для того, что вы имеете в виду, можно сделать, расширив тип массива следующим образом:

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 (как вы, похоже, надеетесь сделать выше).

...