Can someone point me in the right direction on how to implement a simple list with a confirm remove-function or at least show best practice here.
Below code will work if the alert-part is removed and delete action is immediate. Somehow, the presentation of the confirmation-alert makes the the deletion act on the wrong list of persons. First removal also gives a console warning:
[TableView] Warning once only: UITableView was told to layout its visible cells and other contents without being in the view hierarchy (the table view or one of its superviews has not been added to a window). This may cause bugs by forcing views inside the table view to load and perform layout without accurate information (e.g. table view bounds, trait collection, layout margins, safe area insets, etc), and will also cause unnecessary performance overhead due to extra layout passes. Make a symbolic breakpoint at UITableViewAlertForLayoutOutsideViewHierarchy to catch this in the debugger and see what caused this to occur, so you can avoid this action altogether if possible, or defer it until the table view has been added to a window.
However, I have no idea on how to solve this without removing the alert. By the way, this exact code worked a couple of weeks ago before my mac updated xcode i believe.

import Foundation
import SwiftUI
import Combine
struct Person: Identifiable{
var id: Int
var name: String
init(id: Int, name: String){
self.id = id
self.name = name
}
}
class People: ObservableObject{
@Published var people: [Person]
init(){
self.people = [
Person(id: 1, name:"One"),
Person(id: 2, name:"Two"),
Person(id: 3, name:"Three"),
Person(id: 4, name:"Four")]
}
}
struct ContentView: View {
@ObservedObject var mypeople: People = People()
@State private var showConfirm = false
@State private var idx = 0
func setDeletIndex(at idxs:IndexSet) {
self.showConfirm = true
self.idx = idxs.first!
}
func delete() {
self.mypeople.people.remove(at: idx)
}
var body: some View {
VStack {
List {
Text("Currently \(mypeople.people.count) persons").font(.footnote)
.alert(isPresented: $showConfirm) {
Alert(title: Text("Delete"), message: Text("Sure?"),
primaryButton: .cancel(),
secondaryButton: .destructive(Text("Delete")) {
self.delete()
})
}
ForEach(mypeople.people){ person in
Text("\(person.name)")
}.onDelete { self.setDeletIndex(at: $0) }
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
The problem is due to conflict of updating alert closing & List record removing. The working workaround is to delay deleting, as below (tested with Xcode 11.4)
Text("Currently \(mypeople.people.count) persons").font(.footnote)
.alert(isPresented: $showConfirm) {
Alert(title: Text("Delete"), message: Text("Sure?"),
primaryButton: .cancel(),
secondaryButton: .destructive(Text("Delete")) {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) { // here !!
self.delete()
}
})
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With