Damiano Miazzi
Damiano Miazzi

Reputation: 2315

Speed Up a list

I'm try to speed up my APP that for now unfortunately is very slow on performing some search and list of data with Swift Ui.

first of all I have a data model that describe my object airport, called AirportModel

import Foundation

class AirportModel : Identifiable , Codable{
    var aptICAO : String
    var aptName : String
    var aptCity : String
    var aptCountry :String
    var aptIATA : String

init(aptICAO: String, aptName: String, aptCity: String, aptCountry: String, aptIATA: String) {
    self.aptICAO = aptICAO
    self.aptName = aptName
    self.aptCity = aptCity
    self.aptCountry = aptCountry
    self.aptIATA = aptIATA
}

}

I have a local file apt.json, that contain all the data information for my airport (I downloaded from internet this json, inside there are around 29000 airport)

so when I run the first time the app, with the following function , i create and save the airportVector of type AirportModel.

func openfilejson (fileName : String) {
        if let path = Bundle.main.path(forResource: fileName, ofType: "json") {
            do {
                let fileUrl = URL(fileURLWithPath: path)
                let datafile = try Data(contentsOf: fileUrl,options: .mappedIfSafe)
                let json = JSON(data:datafile)
                objectWillChange.send()
                for (key,_) in json {

                    let airport = AirportModel(aptICAO: "", aptName: "", aptCity: "", aptCountry: "", aptIATA: "")
                    airport.aptName = json[key]["name"].stringValue
                    airport.aptCity = json[key]["city"].stringValue
                    airport.aptCountry = json[key]["country"].stringValue
                    airport.aptIATA = json[key]["iata"].stringValue
                    airport.aptICAO = json[key].stringValue
                    airportVector.append(airport)

                }

                debugPrint("nel vettore airport Vector ci sono \(airportVector.count) aeroporti")
                save2() // to save airport vector in the plistfile
                debugPrint("SALVATO IN MEMORIA ")

            } catch {
                 print("ERRORE OPEN FILE AEROPORTI")
            }
        }
    }

all, this work fine , the vector with 29000 airport inside is created once the app is ru the first time.

NOW THE BIG ISSUE.

in one view, I try to list this airport using SwiftUI and a searchBar to search on it.

the problem is, due to the big amount of data to be opened, when I load the View with the list; the data take very long to be listed and moreover when I lunch the search everything is stuck!

any idea how can I process or speed up this huge amount of data to avoid the app stuck on the loading of the following view!


import SwiftUI

struct ContentView: View {
    @ObservedObject var dm: DataManager
    @State private var searchTerm : String = ""
    var body: some View {
        VStack {
            Text("List")
            SearchBar(text: $searchTerm).shadow(radius: 10)
            List(dm.airportVector.filter{
                 $0.aptCity.localizedCaseInsensitiveContains(searchTerm)
                    || $0.aptName.localizedCaseInsensitiveContains(searchTerm)
            }){ item in
                HStack {

                    Text(item.aptICAO).bold().font(Font.system(size:20)).frame(width: 90, height: 10)
                    //
                    Text(item.aptName).font(Font.system(size: 15))
                    Spacer()
                    VStack(alignment: .leading) {

                        Text(item.aptCity).font(Font.system(size: 10)).font(.subheadline)
                        Spacer()
                        Text(item.aptCountry).font(Font.system(size: 10))

                    }
                }
            }
        }
    }
}

Thanks in advance. Damiano

Upvotes: 1

Views: 436

Answers (1)

Gil Birman
Gil Birman

Reputation: 35900

Make your data conform to Identifiable and use ForEach inside of your List with a separate View to render the item:

List {
  ForEach(items) {
    MyItem(item)
  }
}

Only render items when they change by making MyItem conform to Equatable, and define the == function. Make sure the == function is being executed by adding a breakpoint or print statement. If it's not being executed see this article for a workaround:

https://swiftui-lab.com/equatableview/


If the above suggestion works, but you find yourself making wholesale modifications to the list after initial render, try using id() during these modifications. See https://swiftui-lab.com/swiftui-id/


If the above suggestions don't improve things enough, you probably need a more custom solution. Use a TableView or CollectionView, see https://github.com/apptekstudios/ASCollectionView

Upvotes: 1

Related Questions