Xcode Version 13.0 beta 4 (13A5201i)
Please create a new iOS SwiftUI app project, change minimum target to iOS 15. Add a SwiftUI View file HierarchyList
, paste my code into it.
I'm getting "Abort trap 6" when compile. Clear derived data, restarting Xcode do not fix the problem.
Then search for "Uncomment" and uncomment the struct to see this error:
Cannot convert value of type 'Binding.Element' (aka 'Binding<Data.Element>') to expected argument type 'Binding<Data.Element>'
So according to error message, the given type and the expected are the same but the compile "think different"?! :) :)
I am guessing this is due to SE-0293.
// https://gist.github.com/zntfdr/9d94cac84235f04f021cb6c7e8c1a1c5
// Original article here: https://www.fivestars.blog/code/swiftui-hierarchy-list.html
import SwiftUI
struct FileItem: Identifiable {
var name: String
var children: [FileItem]?
let id = UUID()
static let spmData: [FileItem] = [
FileItem(name: ".gitignore"),
FileItem(name: "Package.swift"),
FileItem(name: "README.md"),
FileItem(name: "Sources", children: [
FileItem(name: "fivestars", children: [
FileItem(name: "main.swift")
]),
]),
FileItem(name: "Tests", children: [
FileItem(name: "fivestarsTests", children: [
FileItem(name: "fivestarsTests.swift"),
FileItem(name: "XCTestManifests.swift"),
]),
FileItem(name: "LinuxMain.swift")
])
]
}
struct HierarchyListDemo: View {
@State private var data = FileItem.spmData
var body: some View {
HierarchyList($data: $data, children: \.children, rowContent: { $item in TextField("Edit", text: $item.name) })
}
}
public struct HierarchyList<Data, RowContent>: View where Data: MutableCollection, Data: RandomAccessCollection, Data.Index: Hashable, Data.Element: Identifiable, RowContent: View {
private let recursiveView: RecursiveView<Data, RowContent>
public init(@Binding data: Data, children: KeyPath<Binding<Data.Element>, Binding<Data?>>, rowContent: @escaping (Binding<Data.Element>) -> RowContent) {
self.recursiveView = RecursiveView(data: $data, children: children, rowContent: rowContent)
}
public var body: some View {
List {
recursiveView
}
}
}
// ๐คข๐ ๐๐
// this version uses SE-0293 ForEach w/ @Binding closure parameter. This doesn't compile
// Uncomment this to see compile error that doesn't make sense
//private struct RecursiveView__<Data, RowContent>: View where Data: MutableCollection, Data: RandomAccessCollection, Data.Index: Hashable, Data.Element: Identifiable, RowContent: View {
// @Binding var data: Data
// let children: KeyPath<Binding<Data.Element>, Binding<Data?>>
// let rowContent: (Binding<Data.Element>) -> RowContent
//
// var body: some View {
// ForEach($data) { $item in // ๐๐ compile error: Cannot convert value of type 'Binding<Data>.Element' (aka 'Binding<Data.Element>') to expected argument type 'Binding<Data.Element>'
// if let bindingToChildren = Binding($item[keyPath: children]) {
// DisclosureGroup(content: {
// RecursiveView(data: bindingToChildren, children: children, rowContent: rowContent)
// }, label: {
// rowContent($item)
// })
// } else {
// rowContent($item)
// }
// }
// }
//}
// the above do not compile, so use ForEach(.indices, ...) instead
private struct RecursiveView<Data, RowContent>: View where Data: MutableCollection, Data: RandomAccessCollection, Data.Index: Hashable, Data.Element: Identifiable, RowContent: View {
@Binding var data: Data
let children: KeyPath<Binding<Data.Element>, Binding<Data?>>
let rowContent: (Binding<Data.Element>) -> RowContent
var body: some View {
ForEach(data.indices, id: \.self) { index in
if let bindingToChildren = Binding($data[index][keyPath: children]) {
DisclosureGroup(content: {
RecursiveView(data: bindingToChildren, children: children, rowContent: rowContent)
}, label: {
rowContent($data[index])
})
} else {
rowContent($data[index])
}
}
}
}
struct HierarchyList_Previews: PreviewProvider {
static var previews: some View {
HierarchyListDemo()
}
}
@hborla ?