Search code examples
arrayslistcsvswiftuisearchable

Make a searchable List from CSV file in Swift UI


After long time developing in Swift with storyboard I decide to move to Swift UI. I make a small project to do that. This project is to simply read a CSV file and show some informations in a List and make this list searchable.

I've already been able to read the CSV file and then open some informations in a List. I've understand approximately how the protocol work but I'm definitely looked with the searching function ...

Here is my "mainView" code :

struct AirportView: View {
@State private var searchText = ""
@ObservedObject var airportsVM:AirportsViewModel = AirportsViewModel()
   var body: some View {
       let airportsDB = airportsVM.ListAirports
       NavigationView { 
           List{
               Section(header: Text("Suisse")){
                   Text("Hello World")
               }
               Section(header: Text("France")) {
                   ForEach(airportsDB, id:\.self) { listAirport in
                       
                       NavigationLink(destination: Text(listAirport.ApType)) {
                           Text("\(listAirport.Icao) - \(listAirport.Name)")
                        }
                       
                   }
               }
              
           }
               .id(UUID())
           
       }
       .navigationTitle("Airports")
       .searchable(text: $searchText)
       .navigationViewStyle(StackNavigationViewStyle())
       
   }

and here is my "CSV Reader" Code

    import Foundation

    struct Airports2: Identifiable, Codable, Hashable{
        var AirportID: String = ""
        var Icao: String = ""
        var ApType: String = ""
        var Name: String = ""
        var Latitude: String = ""
        var Longitude: String = ""
        var Altitude: String = ""
        var Continent: String = ""
        var Country: String = ""
        var Region: String = ""
        var Municipality: String = ""
        var Service: String = ""
        var GpsCode: String = ""
        var Iata: String = ""
        var LocalCode: String = ""
        var Link: String = ""
        var wikiLink: String = ""
        var Keyword: String = ""
        let id = UUID()
    }
    var airportsDB = [Airports2]()
    
    class AirportsClass {
        
    
        
        static let 

bundleURL =  Bundle.main.url(forResource: "FR_Airports", withExtension: "csv")!
    static func retrieveAP() -> [Airports2] {
        guard let data = try? Data(contentsOf: bundleURL) else {
            fatalError("Unable to load airports data")
        }
        let decoder = String(data: data, encoding: .utf8)
        if  let dataArr = decoder?.components(separatedBy: "\n").map({ $0.components(separatedBy: ",") })
        {
            var i = 0
            for line in dataArr
            {
                i += 1
                if i <  dataArr.count  {
                    let item = Airports2(AirportID: line[0], Icao: line[1], ApType: line[2], Name: line[3], Latitude: line[4], Longitude: line[5], Altitude: line[6], Continent: line[7], Country: line[8], Region: line[9], Municipality: line[10], Service: line[11], GpsCode: line[12], Iata: line[13], LocalCode: line[14], Link: line[15], wikiLink: line[16], Keyword: line[17])
                    airportsDB.append(item)
                }
            }
        }
        return airportsDB
    }
    }
    
    class AirportsViewModel: NSObject, ObservableObject {
        @Published var ListAirports = [Airports2]()
        override init() {
            
            ListAirports = AirportsClass.retrieveAP()
        }
    }

Thanks for your help !


Solution

  • struct AirportView: View {
        @State private var searchText = ""
        private let airportsVM = AirportsClass.retrieveAP()
    
        var filteredResults: [Airports2] {
            if searchText.isEmpty {
              return airportsVM.ListAirports
            } else {
              // some sort of filtering - you'll probably need to filter on multiple properties
              return airportsVM.ListAirpots.filter { $0.Name.contains(searchText) }
            }
        }
    
        var body: some View {
           NavigationView { 
               List{
                   Section(header: Text("Suisse")){
                       Text("Hello World")
                   }
                   Section(header: Text("France")) {
                       ForEach(filteredResults, id:\.self) { airport in
                           
                           NavigationLink(destination: Text(airport.ApType)) {
                               Text("\(airport.Icao) - \(airport.Name)")
                            }
                           
                       }
                   }
                  
               }
                   .id(UUID())
               
           }
           .navigationTitle("Airports")
           .searchable(text: $searchText)
           .navigationViewStyle(StackNavigationViewStyle())
        }
    }