Working with CSV in Swift (iOS/macOS): From Simple to Complex
CSV (Comma-Separated Values) is one of the most common formats for exchanging tabular data. It is used for exporting from Excel, Google Sheets, databases, and simple logs. In the Swift ecosystem (iOS, macOS, watchOS, tvOS), there is no built-in module for working with CSV, but there are several proven libraries that significantly simplify this process. In this article, we will look at the best tools and write several code examples.
Why you shouldn't write a CSV parser manually?
At first glance, CSV seems simple: split the string by commas and you're done. However, in practice, complications arise:
- Fields may contain commas inside (e.g.,
"Smith, John"). - Fields may be wrapped in quotes, and inside quotes there may be escaped quotes (
""). - Different systems use different delimiters (comma, semicolon, tab).
- Encoding issues (UTF-8, UTF-16, Windows-1251).
Therefore, for production code, it is strongly recommended to use a ready-made library.
Best Libraries for CSV in Swift
1. SwiftCSV (by Naoto Kaneko)
One of the most popular and lightweight libraries. Supports reading and writing, automatically handles quotes and escaping. Works via Swift Package Manager (SPM) and CocoaPods.
// Adding via SPM: .package(url: "https://github.com/naoty/SwiftCSV.git", from: "0.9.0")2. CodableCSV (by Dehesa)
A modern library that integrates with the Codable protocol. Allows parsing CSV directly into Swift structures. Ideal for projects where data has strict typing.
// Adding: .package(url: "https://github.com/dehesa/CodableCSV.git", from: "0.6.0")3. CSwift
A simple and fast library with a minimal API. Well suited for small projects or rapid prototyping.
Example 1: Reading CSV with SwiftCSV
Suppose we have a file users.csv:
id,name,email1,Ivan Ivanov,ivan@example.com2,Maria Petrova,maria@example.com3,John Doe,"john.doe@example.com"Code for reading:
import SwiftCSV
guard let csvURL = Bundle.main.url(forResource: "users", withExtension: "csv") else { print("File not found") return}
do { let csv = try CSV(url: csvURL) // Access rows as an array of dictionaries for row in csv.rows { if let id = row["id"], let name = row["name"], let email = row["email"] { print("ID: \\(id), Name: \\(name), Email: \\(email)") } } // Or access by columns print("All names: \\(csv.columns["name"] ?? [])")} catch { print("Parsing error: \\(error)")}Example 2: Writing CSV with SwiftCSV
import SwiftCSV
let headers = ["Name", "Age", "City"]let rows = [ ["Anna", "28", "Moscow"], ["Boris", "35", "Saint Petersburg"], ["Victor", "22", "Novosibirsk"]]
do { let csv = try CSV(string: "", headers: headers, rows: rows) let csvString = csv.output // Get the CSV string print(csvString) // Save to file let documentsPath = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0] let fileURL = documentsPath.appendingPathComponent("output.csv") try csvString.write(to: fileURL, atomically: true, encoding: .utf8) print("File saved: \\(fileURL)")} catch { print("Write error: \\(error)")}Example 3: CodableCSV — Parsing into Structures
This example shows how easy it is to integrate CSV with data models:
import CodableCSV
struct User: Decodable { let id: Int let name: String let email: String}\