There are a few different methods for scanning a CSV file into your app using Swift. I found that I was able to create my own class method that I thought was the most useful.

I have to apologise because I haven't referenced the internet posts by other developers that helped me out - If I come accross them again then I'll definitely include them!

Here is the class:

import Foundation

class CSVScanner {

    class func debug(string:String){

        println("CSVScanner: \(string)")
    }

    class func runFunctionOnRowsFromFile(theColumnNames:Array<String>, withFileName theFileName:String, withFunction theFunction:(Dictionary<String, String>)->()) {

        if let strBundle = NSBundle.mainBundle().pathForResource(theFileName, ofType: "csv") {

            var encodingError:NSError? = nil

            if let fileObject = NSString(contentsOfFile: strBundle, encoding: NSUTF8StringEncoding, error: &encodingError){

                var fileObjectCleaned = fileObject.stringByReplacingOccurrencesOfString("\r", withString: "\n")

                fileObjectCleaned = fileObjectCleaned.stringByReplacingOccurrencesOfString("\n\n", withString: "\n")

                let objectArray = fileObjectCleaned.componentsSeparatedByString("\n")

                for anObjectRow in objectArray {

                    let objectColumns = anObjectRow.componentsSeparatedByString(",")

                    var aDictionaryEntry = Dictionary<String, String>()

                    var columnIndex = 0

                    for anObjectColumn in objectColumns {

                        aDictionaryEntry[theColumnNames[columnIndex]] = anObjectColumn.stringByReplacingOccurrencesOfString("\"", withString: "", options: NSStringCompareOptions.CaseInsensitiveSearch, range: nil)

                        columnIndex++
                    }

                    if aDictionaryEntry.count>1{
                        theFunction(aDictionaryEntry)
                    }else{

                        CSVScanner.debug("No data extracted from row: \(anObjectRow) -> \(objectColumns)")
                    }
                }
            }else{
                CSVScanner.debug("Unable to load csv file from path: \(strBundle)")

                if let errorString = encodingError?.description {

                    CSVScanner.debug("Received encoding error: \(errorString)")
                }
            }
        }else{
            CSVScanner.debug("Unable to get path to csv file: \(theFileName).csv")
        }
    }
}

You can implement it in your code like this:

var myCSVContents = Array<Dictionary<String, String>>()

    CSVScanner.runFunctionOnRowsFromFile(["title", "body", "category"], withFileName: "fileName.csv", withFunction: {

        (aRow:Dictionary<String, String>) in

        myCSVContents.append(aRow)

    })

This will build an array of Dictionary objects, each representing a row from the CSV. You need to supply an array as the first parameter which contains the header labels of your csv document - make sure you include a label for every column!

However, feel free to skip adding the rows to an Array - you can run any function you like on each row. For instance, you may want to add these directly into a CoreData object.

Thanks for reading my article - please comment or email me if you have any questions!

UPDATE

I have added some error handling to the class to help with debugging - let me know what errors you get back and we can work through it.

Jeremy