How to Read CSV Files and Display as Objects in Desktop Flutter Applications using Swift
In the evolving landscape of cross-platform development, Flutter has made a name for itself, not just in mobile, but also in desktop applications. While Dart is Flutter’s primary language, there are cases when we need to leverage native code, particularly for macOS development where Swift shines. In this guide, we’ll take a deep dive into the process of reading CSV files in Swift and integrating them seamlessly into a Flutter desktop application.
1. Preparation: Understanding Your CSV
First and foremost, it’s paramount that the CSV file is structured consistently. Each row should represent an object, and the first row typically contains headers, representing the property names of objects.
2. Visualizing the Data Structure
Before converting your CSV into Swift-readable objects, visualize a sample object in JSON format. This step aids in generating Swift models in subsequent steps. For instance, your data might look something like:
{
"index":1,
"organizationID":"FAB0d41d5b5d22c",
"name":"Ferrell LLC",
"website":"https://price.net/",
"country":"Papua New Guinea",
"description":"Horizontal empowering knowledgebase",
"founded":1990,
"industry":"Plastics",
"numberOfEmployees":3498
}
3. Swift Model Generation with quicktype.io
- Navigate to quicktype.io.
- Paste your sample JSON.
- Select Swift as the target language.
- This platform quickly generates a Swift model, making data parsing effortless.
4. Flutter Project Configuration in Xcode:
Open the macOS
folder of your Flutter project, which should launch Xcode, as demonstrated in the provided image.
5. Structuring Swift Models:
- Under the
Runner
directory, create aModels
folder. - Inside
Models
, create a new Swift file calledOrganizationModel.swift
. - Copy the model structure from quicktype.io into this file.
- Add an extension to this model to facilitate easier data referencing.
Model with extension
Extension code example
struct OrganizationModel: Codable {
let index: Int
let organizationID, name: String
let website: String
let country, description: String
let founded: Int
let industry: String
let numberOfEmployees: Int
}
extension OrganizationModel {
init?(from row: DataFrame.Row) {
guard let index = row["Index"] as? Int,
let organizationID = row["Organization Id"] as? String,
let name = row["Name"] as? String,
let website = row["Website"] as? String,
let country = row["Country"] as? String,
let description = row["Description"] as? String,
let founded = row["Founded"] as? Int,
let industry = row["Industry"] as? String,
let numberOfEmployees = row["Number of employees"] as? Int else {
return nil
}
self.index = index
self.organizationID = organizationID
self.name = name
self.website = website
self.country = country
self.description = description
self.founded = founded
self.industry = industry
self.numberOfEmployees = numberOfEmployees
}
}
6. Integrating the CSV File:
- Create a directory named
Assets
inside theRunner
directory. - Place your CSV file in this directory, ensuring it’s easily accessible.
7. Data Extraction Logic:
- Inside
Runner
, initiate a new folder titledData
. - Within, create a Swift file named
OrganizationsGet.swift
. This file houses the logic for fetching and processing CSV data. - Here, you’ll use the
TabularData
package. But, if your macOS version target is below 12, you'll receive a warning.
import Foundation
import TabularData
let url = Bundle.main.url(forResource: "organizations", withExtension: "csv")!
var result = try? DataFrame(contentsOfCSVFile: url)
8. Resolving Potential Version Warnings:
If confronted with a version warning:
- Go to Runner => Targets => Runner (Flutter symbol) => minimum deployments.
- Adjust the version to
12.0
.
9. Crafting Data Transfer Functions:
Within OrganizationsGet.swift
, write a getDataFromCsv
function. This function's duty is to parse the CSV data and populate the Swift model.
func getDataFromCsv() -> [OrganizationModel]? {
guard let df = result else {
return nil
}
var organizationModels = [OrganizationModel]()
for row in df.rows {
if let model = OrganizationModel(from: row) {
organizationModels.append(model)
}
}
return organizationModels
}
10. Testing Our Setup:
- Draft a test function named
printOrganizationNames
. - Call this function within the
AppDelegate
and run your project. - If all is well, the console will print the organization names, signifying that our integration is successful.
func printOrganizationNames(from models: [OrganizationModel]) {
for model in models {
print(model.name)
}
}
if let organizationModels = getDataFromCsv() {
printOrganizationNames(from: organizationModels)
}
Sample csv file: Zip version
My github profile: https://github.com/suysoftware