SwiftUI 中的动态列表从 JSON 和 Textfield 更新
Posted
技术标签:
【中文标题】SwiftUI 中的动态列表从 JSON 和 Textfield 更新【英文标题】:Dynamic List in SwiftUI updated from JSON and Textfield 【发布时间】:2020-02-08 15:29:57 【问题描述】:这是我在论坛上的第一条消息,我希望能正确发布。
我正在尝试在 SwiftUI 中创建一个动态列表,只要用户在文本字段中键入内容,它就会立即更新。
该列表使用了来自意大利火车公司的服务 viaggiatreno.it 的 API。
我将使用的特定链接返回以提供给特定 URL 的字符串开头的火车站列表。
我创建了一个 Station Class,如下所示:
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")
谢谢大家
【问题讨论】:
你能解释一下你的意思“我怎样才能在主 SwiftUI 视图中管理这个?你当前的问题是什么?如果它不起作用,最好包含错误。如果它起作用,您认为应该改进哪些方面? 亲爱的 Bart,我实际上并没有在出发视图中加载项目列表,之后,每次我在文本字段中写入内容时,我都需要使其可加载,因为文本字段中的输入将具有与 JSON 不同的结果 【参考方案1】:感谢您提供的帮助。我已经部分成功地完成了我正在寻找的事情,一件事的一部分。
通过在 StationFetcher 中使用 ObservableObject 协议,@Published 到我想更新的变量,我已经更新了列表。
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")
StationFetcher 的代码现在是:
import Foundation
public class StationFetcher : ObservableObject
@Published var stations = [Station]()
init(search: String)
getJsonData(string: search)
func getJsonData(string: String)
stations.removeAll(keepingCapacity: false)
let url = URL(string: "http://www.viaggiatreno.it/viaggiatrenonew/resteasy/viaggiatreno/cercaStazione/" + string.replacingOccurrences(of: " ", with: "%20"))
//string is the initial string of the station name
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)
print(self.stations.count)
else
print("error catching dictionary value")
catch
print("JSON Processing failed")
task.resume()
我唯一没有工作的是列表的实时更新,只要一个字符被数字化。 现在,只要我在文本字段外单击或按回车键,列表就会更新。
我不确定 onEditingChanged 是否是正确的选项。
有人有想法吗?
非常感谢
【讨论】:
【参考方案2】:安东尼奥。您是说要根据用户的搜索输入过滤电台列表吗?我建议进行一些小的更改来实现这一点。
通常在 ObservableObject 中,您可以将 @Published 添加到实例变量中,以使视图在更改时自动更新(例如 @Published var stations = [Station]()
)。但是,因为 StationFetcher 类也符合 Decodable,所以必须自己实现这个发布,可以通过在对象的发布者上调用 send()
来完成:
var stations = [Station]()
didSet
self.objectWillChange.send()
因此,在您的 Departure 视图中,您只需要在用户更改搜索字段时触发新的搜索。这可以通过 TextField 的可选 onEditingChanged
参数来完成,以便在用户键入新文本时执行关闭:
TextField("Da dove parti?...",
text: $selectedStation,
onEditingChanged: _ in
self.fetcher.getJsonData(string: self.selectedStation)
)
让我知道这是否适合你!
【讨论】:
@Antonio85It 嗯,函数被调用了吗?也许将您的 getJsonData 实现与虚拟(非网络)响应交换以查看该部分是否正常工作?另一种方法可能是将 didSet 添加到 selectedStation 谢谢本。它似乎工作但不完全。它会更新“站”的数组,但不会立即重新加载列表。我在 UIKit 中使用 table.reloadData() 管理的内容不起作用。以上是关于SwiftUI 中的动态列表从 JSON 和 Textfield 更新的主要内容,如果未能解决你的问题,请参考以下文章
自学IOS开发第3天·基础SwiftUI之动态滑动列表(上)
自学IOS开发第3天·基础SwiftUI之动态滑动列表(上)
自学IOS开发第3天·基础SwiftUI之动态滑动列表(上)