Post

Replies

Boosts

Views

Activity

Help Loading an External CSV File on iOS in Swift
Hi everyone! I’m fairly new to Swift and currently working on a small iOS app in SwiftUI. The app is able to load a CSV file embedded in the Xcode project (using Bundle.main.path(forResource:)), and everything works well with that. Now, I want to take it a step further by allowing the app to load an external CSV file located in the iPhone’s directories (like “Documents” or “Downloads”). However, I’m struggling to make it work. I tried using a DocumentPicker to select the CSV file, and I believe I’m passing the file URL correctly, but the app keeps reading only the embedded file instead of the one selected by the user. Could anyone offer guidance on how to properly set up loading an external CSV file? I’m still learning, so any suggestions or examples would be really appreciated! Thanks a lot in advance for the help! Here’s the code that isn’t working as expected: import Foundation struct Product: Identifiable { let id = UUID() var codice: String var descrizione: String var prezzo: Double var installazione: Double var trasporto: Double } class ProductViewModel: ObservableObject { @Published var products: [Product] = [] @Published var filteredProducts: [Product] = [] func loadCSV(from url: URL) { products = [] do { let data = try String(contentsOf: url) let lines = data.components(separatedBy: "\n") // Legge e processa ogni riga del CSV (saltando la prima riga se è l'intestazione) for line in lines.dropFirst() { let values = line.components(separatedBy: ";") // Assicurati che ci siano abbastanza colonne e gestisci i valori mancanti if values.count >= 5 { let codice = values[0].trimmingCharacters(in: .whitespaces) let descrizione = values[1].trimmingCharacters(in: .whitespaces) let prezzo = parseEuropeanDouble(values[2]) ?? 0.0 let installazione = parseEuropeanDouble(values[3].isEmpty ? "0,00" : values[3]) ?? 0.0 let trasporto = parseEuropeanDouble(values[4].isEmpty ? "0,00" : values[4]) ?? 0.0 let product = Product( codice: codice, descrizione: descrizione, prezzo: prezzo, installazione: installazione, trasporto: trasporto ) products.append(product) } } filteredProducts = products } catch { print("Errore nel caricamento del CSV: \(error)") } } private func parseEuropeanDouble(_ value: String) -> Double? { let formatter = NumberFormatter() formatter.locale = Locale(identifier: "it_IT") formatter.numberStyle = .decimal return formatter.number(from: value)?.doubleValue } } struct ContentView: View { @StateObject var viewModel = ProductViewModel() @State private var showFilePicker = false var body: some View { VStack { Button("Carica file CSV") { showFilePicker = true } .fileImporter(isPresented: $showFilePicker, allowedContentTypes: [.commaSeparatedText]) { result in switch result { case .success(let url): viewModel.loadCSV(from: url) case .failure(let error): print("Errore nel caricamento del file: \(error.localizedDescription)") } } List(viewModel.filteredProducts) { product in VStack(alignment: .leading) { Text("Codice: \(product.codice)") Text("Descrizione: \(product.descrizione)") Text("Prezzo Lordo: €\(String(format: "%.2f", product.prezzo))") Text("Installazione: €\(String(format: "%.2f", product.installazione))") Text("Trasporto: €\(String(format: "%.2f", product.trasporto))") } } } .padding() } }
1
0
195
2w