Aber R
Aber R

Reputation: 37

Read Json and Add to picker swiftUI

  struct Test: View {
    
    @ObservedObject var datas2 = ReadData2()
    @State var selectedIndex2 = 0
    
     var body: some View {
                VStack{
                    List{
                            HStack{
                                Text("From")
                                    .foregroundColor(Color("Color"))
                                    .fontWeight(.bold)
                                    .font(.system(size: 20))
                                    .padding(.leading, 10.0)
                                    .frame(width: nil, height: nil, alignment: .leading)
                                Picker(selection: $selectedIndex2, label: Text("")) {
                                    ForEach(0 ..< datas2.cities.count, id: \.self) {
                                        Text(datas2.cities[$0].name)
                                        
                                    }
                                }.foregroundColor(Color("Color"))
                                    .padding(.trailing)
    }
    }
    }
}
    struct City: Codable, Identifiable {
            enum CodingKeys: CodingKey {
                case name
            }
            
            var id = UUID()
            var name: String
        }
        class ReadData2: ObservableObject  {
           @Published var cities = [City]()
           
           
           init(){
               loadData()
           }
           
           func loadData()  {
               guard let url = Bundle.main.url(forResource: "cities", withExtension: "json")
               else {
                   print("Json file not found")
                   return
               }
               
               let data = try? Data(contentsOf: url)
               let cities = try? JSONDecoder().decode([City].self, from: data!)
               self.cities = cities!
               
           }
           
       }

and I have a json file called cities that is like this :

{
    "country": "AD",
    "name": "Sant Julià de Lòria",
    "lat": "42.46372",
    "lng": "1.49129"
  },
  {
    "country": "AD",
    "name": "Pas de la Casa",
    "lat": "42.54277",
    "lng": "1.73361"
  },
  {
    "country": "AD",
    "name": "Ordino",
    "lat": "42.55623",
    "lng": "1.53319"
  },
  {
    "country": "AD",
    "name": "les Escaldes",
    "lat": "42.50729",
    "lng": "1.53414"
  },
  {
    "country": "AD",
    "name": "la Massana",
    "lat": "42.54499",
    "lng": "1.51483"
  },

My problem is that cites are too much data, and once I press the picker it takes a long time to read data and post data inside the picker, is there a better way for making it faster ?
and I am trying to make it searchable throught a search text taking the first letter of the city and it is not working ! I hope you can help me !

Upvotes: 0

Views: 116

Answers (1)

With very large number of items, I would suggest using a List or a LazyVStack that are optimised for that, instead of a Picker. Something like the following example code. Note, you will have to adjust the UI for your purpose.

struct ContentView: View {
    var body: some View {
        Test()
    }
}

struct Test: View {
    @StateObject var datas2 = ReadData2()
    @State var selectedCity: City?
    @State private var searchQuery: String = ""
    
    var body: some View {
        VStack (spacing: 20) {
            TextField("city search", text: $searchQuery).padding(5)
                .overlay(RoundedRectangle(cornerRadius: 15).stroke(Color.blue, lineWidth: 1))
                .foregroundColor(.blue)
                .frame(width: 160)
                .padding(.top, 20.0)
            
            HStack {
                Text("From")
                    .fontWeight(.bold)
                    .font(.system(size: 20))
                    .padding(.leading, 10.0)
                Spacer()
                ScrollView {
                    LazyVStack {
                        ForEach(datas2.cities.filter{searchFor($0.name)}.sorted(by: { $0.name < $1.name })) { city in
                            Text(city.name).foregroundColor(selectedCity == city ? .red : .blue)
                                .onTapGesture {
                                    selectedCity = city
                                }
                        }
                    }
                }.frame(width: 222, height: 111)
            }
            Spacer()
        }
    }
    
    private func searchFor(_ txt: String) -> Bool {
        return (txt.lowercased(with: .current).hasPrefix(searchQuery.trimmingCharacters(in: .whitespacesAndNewlines).lowercased(with: .current)) || searchQuery.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty)
    }
}
struct City: Codable, Identifiable, Hashable {
    enum CodingKeys: CodingKey {
        case name
    }

    var id = UUID()
    var name: String
}

class ReadData2: ObservableObject  {
    @Published var cities = [City]()
    
    init() {
        loadData()
    }
    
    func loadData() {
        if let url =  Bundle.main.url(forResource: "cities", withExtension: "json") {
            do {
                let data = try Data(contentsOf: url)
                cities = try JSONDecoder().decode([City].self, from: data)
            } catch {
                print(" error:\(error)")
            }
        }
    }
}

Upvotes: 1

Related Questions