Working with Data
Learn how to provide data to your table using type-safe or array-based APIs.
Two Approaches
SwiftDataTables supports two approaches for providing data:
- Type-safe API - Define columns using KeyPaths on your model types. Requires
Identifiableconformance, enabling animated updates when data changes. - Array-based API - Pass a 2D array of strings for simple static displays. No model required.
Choose the type-safe API when you have model types and want diffing/animations. Choose the array-based API for quick prototyping or truly static data.
Static Displays
For simple tables where data doesn't change, use the array-based initializer:
let data: [[String]] = [
["Alice", "Engineering", "Senior"],
["Bob", "Marketing", "Manager"],
["Carol", "Sales", "Associate"]
]
let headers = ["Name", "Department", "Role"]
let dataTable = SwiftDataTable(data: data, headerTitles: headers)Type-Safe API with Models
The type-safe API works directly with your model types. The key requirement: models must conform to Identifiable.
struct Person: Identifiable {
let id: Int // Already have a unique ID? You're done.
let name: String
let email: String
let department: String
}
let columns: [DataTableColumn<Person>] = [
.init("Name", \.name),
.init("Email", \.email),
.init("Department", \.department)
]
let dataTable = SwiftDataTable(data: people, columns: columns)The id property enables diffing. Without it, SwiftDataTables can't determine which rows changed.
Loading and Updating Data
// Initial load
let people = await fetchPeople()
dataTable.setData(people, animatingDifferences: true)
// Later, when data changes
let updatedPeople = await fetchPeople()
dataTable.setData(updatedPeople, animatingDifferences: true) // Only changed rows animateSwiftDataTables compares the old and new arrays by ID, then:
- Animates insertions and deletions
- Updates changed rows in place
- Leaves unchanged rows alone
- Preserves scroll position
Data Transformations
Formatting Values
let columns: [DataTableColumn<Product>] = [
.init("Product", \.name),
.init("Price") { String(format: "$%.2f", $0.price) },
.init("In Stock") { $0.inStock ? "Yes" : "No" }
]Date Formatting
let dateFormatter: DateFormatter = {
let f = DateFormatter()
f.dateStyle = .medium
return f
}()
let columns: [DataTableColumn<Event>] = [
.init("Event", \.name),
.init("Date") { dateFormatter.string(from: $0.date) }
]CSV and JSON Data
When the schema isn't known at compile time, create a simple wrapper struct:
struct CSVRow: Identifiable {
let id: Int // Row index as ID
let values: [String] // Column values
}
func loadCSV(from url: URL) {
let csvData = parseCSV(url)
let headers = csvData.headers
// Create columns dynamically
let columns: [DataTableColumn<CSVRow>] = headers.enumerated().map { index, header in
.init(header) { row in
row.values[index]
}
}
// Create rows with index as ID
let rows = csvData.rows.enumerated().map { index, values in
CSVRow(id: index, values: values)
}
dataTable = SwiftDataTable(data: rows, columns: columns)
}