ForEach and RandomAccessCollection

I'm trying to build a custom FetchRequest that I can use outside a View. I've built the following ObservableFetchRequest class based on this article: https://augmentedcode.io/2023/04/03/nsfetchedresultscontroller-wrapper-for-swiftui-view-models

@Observable @MainActor class ObservableFetchRequest<Result: Storable>: NSObject, @preconcurrency NSFetchedResultsControllerDelegate {
private let controller: NSFetchedResultsController<Result.E>
private var results: [Result] = []
init(context: NSManagedObjectContext = .default, predicate: NSPredicate? = Result.E.defaultPredicate(), sortDescriptors: [NSSortDescriptor] = Result.E.sortDescripors) {
guard let request = Result.E.fetchRequest() as? NSFetchRequest<Result.E> else {
fatalError("Failed to create fetch request for \(Result.self)")
}
request.predicate = predicate
request.sortDescriptors = sortDescriptors
controller = NSFetchedResultsController(fetchRequest: request, managedObjectContext: context, sectionNameKeyPath: nil, cacheName: nil)
super.init()
controller.delegate = self
fetch()
}
private func fetch() {
do {
try controller.performFetch()
refresh()
}
catch {
fatalError("Failed to fetch results for \(Result.self)")
}
}
private func refresh() {
results = controller.fetchedObjects?.map { Result($0) } ?? []
}
var predicate: NSPredicate? {
get {
controller.fetchRequest.predicate
}
set {
controller.fetchRequest.predicate = newValue
fetch()
}
}
var sortDescriptors: [NSSortDescriptor] {
get {
controller.fetchRequest.sortDescriptors ?? []
}
set {
controller.fetchRequest.sortDescriptors = newValue.isEmpty ? nil : newValue
fetch()
}
}
internal func controllerDidChangeContent(_ controller: NSFetchedResultsController<any NSFetchRequestResult>) {
refresh()
}
}

Till this point, everything works fine.

Then, I conformed my class to RandomAccessCollection, so I could use in a ForEach loop without having to access the results property.

extension ObservableFetchRequest: @preconcurrency RandomAccessCollection, @preconcurrency MutableCollection {
subscript(position: Index) -> Result {
get {
results[position]
}
set {
results[position] = newValue
}
}
public var endIndex: Index { results.endIndex }
public var indices: Indices { results.indices }
public var startIndex: Index { results.startIndex }
public func distance(from start: Index, to end: Index) -> Int {
results.distance(from: start, to: end)
}
public func index(_ i: Index, offsetBy distance: Int) -> Index {
results.index(i, offsetBy: distance)
}
public func index(_ i: Index, offsetBy distance: Int, limitedBy limit: Index) -> Index? {
results.index(i, offsetBy: distance, limitedBy: limit)
}
public func index(after i: Index) -> Index {
results.index(after: i)
}
public func index(before i: Index) -> Index {
results.index(before: i)
}
public typealias Element = Result
public typealias Index = Int
}

The issue is, when I update the ObservableFetchRequest predicate while searching, it causes a Index out of range error in the Collection subscript because the ForEach loop (or a List loop) access a old version of the array when the item property is optional.

List(request, selection: $selection) { item in
VStack(alignment: .leading) {
Text(item.content)
if let information = item.information { // here's the issue, if I leave this out, everything works
Text(information)
.font(.callout)
.foregroundStyle(.secondary)
}
}
.tag(item.id)
.contextMenu {
if Item.self is Client.Type {
Button("Editar") {
openWindow(ClientView(client: item as! Client), id: item.id!)
}
}
}
}

Is it some RandomAccessCollection issue or a SwiftUI bug?

ForEach and RandomAccessCollection
 
 
Q