'Safe handling of Apple TabularData table data in Swift

I have successfully imported a simple two-column CSV file using DataFrame. Now I want to turn the two cells in each row into strings. The left or right side will occasionally be missing a value; see print output. table

When I try to process a row with a nil cell, the program crashes with "Fatal error: Unexpectedly found nil while unwrapping an Optional value"

So my question is, how do I turn the cells into strings ("" if Nil) safely?

Complete ContentView code below, thanks in advance for any help.

import SwiftUI
import TabularData

struct ContentView: View {
    @State var openFile = false

var body: some View {
    VStack {
        
        Button(action: {openFile.toggle()}, label: {
            Text("Open")
        })
    }.fileImporter(
        isPresented: $openFile,
        allowedContentTypes: [.commaSeparatedText],
        allowsMultipleSelection: false) { (result) in
            do {
                let fileURL = try result.get().first
                if fileURL!.startAccessingSecurityScopedResource() {
                    print(fileURL!)
                    importTable(url: fileURL!)
                }
                fileURL!.stopAccessingSecurityScopedResource()
            } catch {
                print("Unable to read file contents")
                print(error.localizedDescription)
            }
        }
}

func importTable(url: URL) {
    
    var importerTable: DataFrame = [:]
    
    let options = CSVReadingOptions(hasHeaderRow: false, delimiter: ",")
    do {
        importerTable = try DataFrame(
            contentsOfCSVFile: url,
            options: options)
    } catch {
        print("ERROR reading CSV file")
        print(error.localizedDescription)
    }
    
    print("\(importerTable)")
    
    importerTable.rows.forEach { row in
        let leftString = row[0]! as! String
        let rightString = row[1]! as! String
        
        print("Left: \(leftString) Right: \(rightString)")
        }
    }
}


Solution 1:[1]

A fileImporter context is quite insecure, any carelessly written exclamation mark can crash the app.

First you have to check fileURL and abort the import if it's nil

guard let fileURL = try result.get().first else { return }
if fileURL.startAccessingSecurityScopedResource() {
    print(fileURL)
    importTable(url: fileURL)
}
fileURL.stopAccessingSecurityScopedResource()

In importTable you must not continue after a do - catch if an error is thrown and you have to check if the CSV file contains three items per row.

func importTable(url: URL) {
    
    var importerTable: DataFrame = [:]
    
    let options = CSVReadingOptions(hasHeaderRow: false, delimiter: ",")
    do {
        importerTable = try DataFrame(
            contentsOfCSVFile: url,
            options: options)

        print("\(importerTable)")
    
        importerTable.rows.forEach { row in
            if row.count > 2 {
                let leftString = row[1] as! String
                let rightString = row[2] as! String
            
                print("Left: \(leftString) Right: \(rightString)")
            }
        }
    } catch {
        print("ERROR reading CSV file")
        print(error.localizedDescription)
    }
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1