Home > Mobile >  SwiftUI download CSV from Web and got data into an array
SwiftUI download CSV from Web and got data into an array

Time:11-23

I am trying to download a CSV file from my own apps web server to store in a array. The CSV contain all the Image URL for my app but also the name of the image, the latitude and the longitude. He is regularly updated and he is formatted like this :

Name;URL;Latitude;Longitude

The CSV URL is : http://apps.e-rochoise.fr/ressources/imageTest.csv

And I would like to add it into an array where Name is String, URL is URL, Latitude and longitude is Double.

I've trying to do this code to download my CSV in a local folder. This code works the first time but I'm not able to overwrite the new CSV when I call for a new time my function.

func downloadCsvFromURL(){

let documentsUrl:URL =  (FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first as URL?)!

    
    let destinationFileUrl = documentsUrl.appendingPathComponent("FR_Airports.csv")
    
    let fileURL = URL(string: "https://apps.e-rochoise.fr/ressources/imageTest.csv")
    
    let sessionConfig = URLSessionConfiguration.default
    let session = URLSession(configuration: sessionConfig)
 
    let request = URLRequest(url:fileURL!)
    
    let task = session.downloadTask(with: request) { (tempLocalUrl, response, error) in
        if let tempLocalUrl = tempLocalUrl, error == nil {
            if let statusCode = (response as? HTTPURLResponse)?.statusCode {
                print("Successfully downloaded. Status code: \(statusCode)")
            }
            
            do {
                try FileManager.default.copyItem(at: tempLocalUrl, to: destinationFileUrl)
            } catch (let writeError) {
                print("Error creating a file \(destinationFileUrl) : \(writeError)")
            }
            
        } else {
            print("Error" )
        }
    }
    task.resume()

}

And Now I don't know how to define my array to be accessible in all the app ...

Thanks for your help !!

CodePudding user response:

Rather than loading and moving the data with downloadTask I recommend to load the data with dataTask and write it directly to the destination. The benefit is write(to of Data overwrite an existing file.

The URLRequest and the custom – which is actually the default – session configuration is not needed

func downloadCsvFromURL() {
    
    let documentsUrl = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
    let destinationFileUrl = documentsUrl.appendingPathComponent("FR_Airports.csv")
    let fileURL = URL(string: "https://apps.e-rochoise.fr/ressources/imageTest.csv")!
  
    let task = URLSession.shared.dataTask(with: fileURL) { (data, response, error) in
        if let data = data {
            if let statusCode = (response as? HTTPURLResponse)?.statusCode {
                print("Successfully downloaded. Status code: \(statusCode)")
            }
            
            do {
                try data.write(to: destinationFileUrl)
            } catch  {
                print("Error creating a file \(destinationFileUrl) : \(error)")
            }
        } else {
            print(error!)
        }
    }
    task.resume()
}

To parse the data create a struct

struct Item {
    let name: String
    let url : URL
    let latitude, longitude : Double
}

then make a string from data, split it into lines and split each line by the semicolons. As the latitude and longitude values are localized (comma decimal separator) you have to replace comma by period to be able to create a Double

let csv = String(data: data, encoding: .utf8)!.components(separatedBy: .newlines)
for line in csv {
    let fields = line.components(separatedBy: ";")
    if fields.count == 4 {
        let name = fields[0]
        let url = fields[1]
        let lat = fields[2].replacingOccurrences(of: ",", with: ".")
        let lon = fields[3].replacingOccurrences(of: ",", with: ".")
        let item = Item(name: name,
                        url: URL(string: url)!,
                        latitude: Double(lat)!,
                        longitude: Double(lon)!)
        print(item)
    }
    
}

Instead of the print(item) line you could add the item to a collection type.

  • Related