How it works
DynamicTableRowContent is the protocol that table row builders adopt when their rows aren't fixed at compile time but are produced from a collection of data. Where a static TableRow stands in for a single known element, conformers to this protocol describe a whole family of rows generated one-per-element, keeping each row tied to its underlying identified value. Reach for it whenever a Table needs to grow, shrink, or reorder its rows in step with a data source rather than enumerating them by hand. In practice you rarely name the protocol directly — you obtain a conforming value by iterating your data inside the table's row builder.
Generate rows from data with ForEach
The canonical source of dynamic row content is ForEach, whose result conforms to DynamicTableRowContent. Placed in the row builder, it visits each element of a collection and emits one row apiece, so the table's contents track the array. Here
ForEach(fruits)walks the threeFruitvalues and produces a row for each.Emit one TableRow per element
Inside the dynamic builder you return a TableRow for the current element, binding that row to a specific value. The row carries the data that each TableColumn then reads when it renders a cell. In the example
TableRow($0)wraps the per-iterationFruit, becoming the unit of dynamic content that DynamicTableRowContent represents.Identify each row so updates stay stable
Dynamic row content relies on stable identity to diff, animate, and select rows as the data changes. Conforming your model to Identifiable supplies that identity automatically.
Fruitdeclareslet id = UUID(), which letsForEach(fruits)and itsTableRowvalues match rows to elements across reloads without an explicit id key path.Place the content in the table's rows builder
DynamicTableRowContent slots into the trailing
rows:closure of a Table built from a row type, while the columns closure stays separate. TheTable(of: Fruit.self)form pairs theTableColumndefinitions with the dynamic rows, soForEach(fruits) { TableRow($0) }is the value satisfying the row-content requirement and$0.name,$0.countare resolved column-by-column.
Fruit(name:count:) entry to the fruits array and watch a new row appear without touching the Table or TableColumn code — the dynamic row content regenerates from the data.Example & preview
Press Run live & edit to compile it in your browser — then edit the Swift on the left and the preview re-renders live.
struct DynamicTableRowContentDemo: View {
struct Fruit: Identifiable {
let id = UUID()
let name: String
let count: Int
}
let fruits = [
Fruit(name: "Apple", count: 12),
Fruit(name: "Banana", count: 7),
Fruit(name: "Cherry", count: 30)
]
var body: some View {
Table(of: Fruit.self) {
TableColumn("Name") { Text($0.name) }
TableColumn("Count") { Text("\($0.count)") }
} rows: {
ForEach(fruits) { TableRow($0) }
}
.padding()
}
}