SwiftUI中的动态列表已从JSON和Textfield更新

时间:2020-02-08 15:29:57

标签: json swiftui

这是我在论坛上的第一条消息,我希望将其正确张贴。

我正在尝试在SwiftUI中创建一个动态列表,一旦用户在文本字段中键入内容,该列表就会立即更新。

列表使用viaggiatreno.it的API,这是意大利火车公司的服务。

我将使用的特定链接返回以提供给特定URL的字符串开头的火车站列表。

我已经创建了一个车站类,如下所示:

struct Station: Decodable, Identifiable {
    var iid = UUID()
    var name : String
    var id: String
}

还有一个StationFetcher类,该类获取用字符串初始化的API URL,该字符串是用户将从文本字段传递的字符串:

import Foundation

public class StationFetcher : Decodable, ObservableObject {

    var stations = [Station]()
    var search = ""

    init(search: String) {
        getJsonData(string: search)
    }

    func getJsonData(string: String) {

        let url = URL(string: "http://www.viaggiatreno.it/viaggiatrenonew/resteasy/viaggiatreno/cercaStazione/" + string) 
//string is the initial string of the station
            let task = URLSession.shared.dataTask(with: url!) { (data, response, error) in
                if error != nil {
                    print(error!)
                } else {
                    if let urlContent = data {
                        do {
                            let jsonResult = try JSONSerialization.jsonObject(with: urlContent , options: JSONSerialization.ReadingOptions.mutableContainers) as AnyObject
                            for i in 0..<jsonResult.count {
                                if let station = jsonResult[i] as AnyObject? {
                                    if let nameStation = station["nomeLungo"] as! String? {
                                        if let idStation = station["id"] as! String? {
                                            let searchItem = Station(name: nameStation, id: idStation)
                                            DispatchQueue.main.async {
                                                self.stations.append(searchItem)
                                            }
                                        }
                                    } else {
                                        print("error catching dictionary value")
                                    }
                                }
                            }
                        } catch {
                            print("JSON Processing failed")

                        }
                    }
                }

            }
            task.resume()
        }
    }

如何在主SwiftUI视图中进行管理?

import SwiftUI

struct Departure: View {
    @State public var selectedStation = ""
    @State private var departureDate = Date()
    @ObservedObject var fetcher = StationFetcher(search: "")

    var body: some View {
        NavigationView {
            Form {
                Section(header: Text("Cerca Stazione di partenza:")) {
                    TextField("Da dove parti?...", text: $selectedStation)
                }
                Section(header: Text("Orario:")) {
                    DatePicker(selection: $departureDate) {
                        Text("Partenza")
                    }
                }
                Section(header: Text("Lista stazioni")){
                    List(fetcher.stations) { station in
                        Text(station.name)
                    }
                }
            }
        .navigationBarTitle("Partenza")
        }
    }
}

谢谢大家

2 个答案:

答案 0 :(得分:1)

感谢您的帮助。我已经部分成功地完成了我要寻找的东西,一部分是为了一件事情。

通过在StationFetcher中使用ObservableObject协议,将@Publish发布到我要更新的变量中,即可更新列表。

test.js

StationFetcher的代码现在为:

struct Departure: View {
    @State public var selectedStation = ""
    @State private var departureDate = Date()
    @ObservedObject var fetcher = StationFetcher(search: "")

    var body: some View {
        NavigationView {
            Form {
                Section(header: Text("Cerca Stazione di partenza:")) {
                    TextField("Da dove parti?...",
                              text: $selectedStation, onEditingChanged: { _ in
                                self.fetcher.getJsonData(string: self.selectedStation)
                    })
                }
                Section(header: Text("Orario:")) {
                    DatePicker(selection: $departureDate) {
                        Text("Partenza")
                    }
                }
                Section(header: Text("Lista stazioni")){
                    List(fetcher.stations) { station in
                        Text(station.name)
                            .autocapitalization(.words)
                    }
                }
            }
        .navigationBarTitle("Partenza")
        }
    }
}

我唯一无法使用的是对一个字符进行数字化后立即实时更新列表。 现在,只要我在文本字段之外单击或按回车键,该列表就会更新。

我不确定onEditingChanged是否正确。

有人有主意吗?

非常感谢

答案 1 :(得分:0)

安东尼奥。您是说要根据用户的搜索输入来过滤电台列表吗?我建议进行一些小的更改以使这种情况发生。

通常,在ObservableObject中,您可以将@Published添加到实例变量,以使视图在更改时自动更新(例如@Published var stations = [Station]())。但是,由于StationFetcher类也符合Decodable,因此您必须自己实现此发布,这可以通过在对象的发布者上调用send()来完成:

var stations = [Station]() {
    didSet {
        self.objectWillChange.send()
    }
}

因此,在您的出发视图中,您只需要在用户更改搜索字段时触发新搜索。可以使用TextField的可选onEditingChanged参数来完成此操作,以在用户键入新文本时执行关闭操作:

TextField("Da dove parti?...",
          text: $selectedStation,
          onEditingChanged: { _ in
            self.fetcher.getJsonData(string: self.selectedStation)
})

让我知道这是否适合您!