Dynami c Список в SwiftUI обновлен с JSON и текстового поля - PullRequest
0 голосов
/ 08 февраля 2020

это мое первое сообщение на форуме, и я надеюсь опубликовать его правильно.

Я пытаюсь создать список Dynami c в SwiftUI, который обновляется, как только пользователь вводит что-то внутри textfield.

В списке используется API-интерфейс viaggiatreno.it, который является службой итальянской железнодорожной компании.

Указанная ссылка c, которую я буду использовать, возвращает список железнодорожных станций, которые Начните со строки, предоставленной для определенного URL.

Я создал класс Station следующим образом:

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

И класс StationFetcher, который выбирает URL-адрес API, инициализированный строкой, которая является строка, которую пользователь передаст из текстового поля:

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 ]

1 голос
/ 09 февраля 2020

спасибо за предоставленную помощь. Мне частично удалось сделать то, что я ищу, часть для одной вещи.

Используя протокол ObservableObject в StationFetcher, @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 правильным вариантом.

Есть ли у кого-нибудь идея?

Большое спасибо

0 голосов
/ 09 февраля 2020

Антонио. Вы говорите, что хотите отфильтровать список станций по поисковому вводу пользователя? Я бы предложил пару небольших изменений, чтобы это произошло.

Как правило, в ObservableObject вы можете добавить @Published к переменной экземпляра, чтобы представления автоматически обновлялись при ее изменении (например, @Published var stations = [Station]()). Однако, поскольку класс StationFetcher также соответствует Decodable, вы должны реализовать эту публикацию самостоятельно, что можно сделать, вызвав send() у издателя объекта:

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

Итак, в представлении «Отправление» вы просто нужно инициировать новый поиск, когда пользователь меняет поле поиска. Это можно сделать с помощью необязательного параметра onEditingChanged для TextField, чтобы выполнить закрытие, когда пользователь вводит новый текст:

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

Дайте мне знать, если это работает для вас!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...