1

I have text file which contains 18000 lines which have cities names. Each line has city name, state, latitude, longitude etc. Below is the function which does that, if i don't implement string.components(separtedBy: ", ") loading function is pretty fast but with it implemented it takes time which makes my UI freeze. What is the right way of doing it? Is string.components(separtedBy: ", ") that costly?

I profiled the app, this line is taking string.components(separtedBy: ", ") 1.45s out of 2.09s in whole function.

func readCitiesFromCountry(country: String) -> [String] {
        var cityArray: [String] = []
        var flag = true
        var returnedCitiesList: [String] = []

        if let path = Bundle.main.path(forResource: country, ofType: "txt") {
            guard let streamReader = StreamReader(path: path) else {fatalError()}
            defer {
                streamReader.close()
            }
            while flag {
                if let nextLine = streamReader.nextLine() {
                    cityArray = nextLine.components(separatedBy: ",") // this is the line taking a lot of time, without this function runs pretty fast
                    if (country == "USA") {
                        returnedCitiesList.append("\(cityArray[0]) , \(cityArray[1]) , \(cityArray[2])")
                    } else {
                        returnedCitiesList.append("\(cityArray[0]) , \(cityArray[1])")
                    }
                   //returnedCitiesList.append(nextLine)
                } else {
                    flag = false
                }
            }
        } else {
            fatalError()
        }

        return returnedCitiesList
    }

StreamReader used in the code can be found here. It helps to read file line by line Read a file/URL line-by-line in Swift

This question is not about how to split the string into array Split a String into an array in Swift? , rather why splitting is taking more time in the given function.

John
  • 31
  • 5

1 Answers1

0

NSString.components(separatedBy:) returns a [String], which requires that all of the pieces' content be copied, from the original string, and pasted into new-ly allocated stringss. This slows things down.

You could address the symptoms (UI freezing) by putting this work on a background thread, but that just sweeps the problem under the wrong (the inefficient copying is still there), and complicates things (async code is never fun).

Instead, you should consider using String.split(separator:maxSplits:omittingEmptySubsequences:), which returns [Substring]. Each Substring is just a view into the original string's memory, which stores the relevant range so that you only see that portion of the String which is modeled by the Substring. The only memory allocation happening here is for the array.

Hopefully that should be enough to speed your code up to acceptable levels. If not, you should combine both solutions, and use split off-thread.

Alexander
  • 59,041
  • 12
  • 98
  • 151