Sorting of items in a hierarchical table does not work!
Model
struct File: Decodable {
/*File name (including relative path)*/
let name: String
/*File size (bytes)*/
let size: Int64
var children: [File]?
}
extension File: Identifiable {
var id: String { name } // unic for node
}
Table
struct TableView: View {
@Environment(AppContext.self) private var appContext
@State private var fileTree: [File] = []
@State private var sortOrder = [KeyPathComparator(\File.name)]
@State private var selectedFile: Set<String> = Set()
var body: some View {
Table(fileTree, children: \.children, selection: $selectedFile, sortOrder: $sortOrder) {
TableColumn("Name", value: \.name) { file in
ItemName(for: file)
.padding(.leading, 5)
}
.width(ideal: 300)
TableColumn("Size", value: \.size) {
Text($0.size, format: .byteCount(style: .memory, spellsOutZero: false))
.frame(maxWidth: .infinity, alignment: .trailing)
}
.width(ideal: 50)
}
.onChange(of: sortOrder) { _, newValue in
fileTree.sort(using: newValue)
}
}
}
However, sorting only works for the root elements. Is there something I'm missing?
As you may already know, Table
doesn't do any sorting for you. The sorting should be done by you, in onChange(of: sortOrder)
. You are doing fileTree.sort(using: newValue)
, which of course sorts the root elements.
You need to write your own sorting logic that also sorts the files' children. If you want to sort each children
array individually and recursively, you can write an extension like so:
extension MutableCollection where Self: RandomAccessCollection {
mutating func recursiveSort<S, Comparator>(
using comparators: S,
children: WritableKeyPath<Element, Self?>
) where
S : Sequence,
Comparator : SortComparator,
Comparator == S.Element,
Element == Comparator.Compared
{
sort(using: comparators)
for i in indices {
self[i][keyPath: children]?.recursiveSort(using: comparators, children: children)
}
}
}
Usage:
.onChange(of: sortOrder) { _, newValue in
fileTree.recursiveSort(using: newValue, children: \.children)
}