onDelete在SwiftData NavigationSplitView中不能可靠地删除列表项。

huangapple go评论80阅读模式
英文:

onDelete Does not Reliably Delete List Items in SwiftData NavigationSplitView

问题

我正在使用SwiftData构建一个新版本的应用程序,并在iPad横向模式下删除列表时遇到问题。在删除项目时,已删除的项目会随机重新出现,就好像没有从上下文中删除一样。我已经包含了一个非常简单的示例代码来说明这个问题。如果你随机选择一行,然后通过滑动删除另一行并继续测试其他序列,你会发现已删除的行经常会在选择另一行时消失,然后重新出现。

我当然知道这是Beta软件,但这似乎相当基础,所以我想知道我是否在SwiftData设置或我以前使用的.onDelete代码中漏掉了什么。这种行为在Beta 4和Beta 5中都是相同的。

struct ContentView: View {
    @Environment(\.modelContext) private var context
    @Query(sort: \Thing.name, order: .forward) var things: [Thing]
    @State private var selectedThing: Thing?

    var body: some View {
        NavigationSplitView {
            VStack {
                Text("Some Things")
                List(selection: $selectedThing) {
                    ForEach(things, id: \.self) { thing in
                        HStack {
                            Text(thing.name)
                            Text(thing.areYouSure.description)
                        }
                    }//for each
                    .onDelete { indexSet in
                        indexSet.forEach { index in
                            if things[index] == selectedThing {
                                context.delete(things[index])
                                do {
                                    try context.save()
                                } catch {
                                    print(error)
                                }
                            }
                        }
                    }//on delete
                }//list
            }//v
            .toolbar {
                ToolbarItem(placement: .topBarTrailing) {
                    Button {
                        AddFourThings()
                    } label: {
                        Image(systemName: "plus")
                    }
                }
            }
        } detail: {//nav split sidebar
            ZStack {
                if let selectedThing = selectedThing {
                    DetailView(thing: selectedThing)
                } else {
                    Text("Choose a Thing")
                }
            }
        }//nav split detail
    }//body

    private func AddFourThings() {
        let thing1 = Thing(name: "Thing One", areYouSure: true)
        let thing2 = Thing(name: "Thing Two", areYouSure: false)
        let thing3 = Thing(name: "Thing Three", areYouSure: true)
        let thing4 = Thing(name: "Thing Four", areYouSure: false)
        
        context.insert(thing1)
        context.insert(thing2)
        context.insert(thing3)
        context.insert(thing4)
    }//add four
}//struct

struct DetailView: View {
    @State private var isOn: Bool = false
    var thing: Thing

    var body: some View {
        VStack {
            Text(thing.name)
                .font(.title)
            Text(thing.areYouSure.description)
                .font(.title)
            Text(isOn.description)
                .font(.title)
            Toggle("Toggle Me", isOn: $isOn)
                .font(.title)
        }
    }
}//detail view

@Model
class Thing: Identifiable {
    var name: String
    var areYouSure: Bool
    
    init(name: String, areYouSure: Bool) {
        self.name = name
        self.areYouSure = areYouSure
    }
}//class Thing

希望这些指导对你有帮助。Xcode 15.0 beta 4 (15A5195m),iOS 17.

英文:

I'm building a new version of an app with SwiftData and am having issues with list deletions in iPad landscape mode. When deleting items, the deleted item randomly reappears as though not deleted from the context. I have included code for a very simple example to illustrate the issue. If you randomly select a row, then delete another row by swipe to delete and continue testing other sequences you will find that the deleted rows often disappear only to reappear when another row is selected.

I realize, of course, this is Beta software, but this seems pretty basic so I'm wondering if I have missed something in the SwiftData setup or the .onDelete code that I have used it in the past. The behavior is the same for Beta 4 and Beta 5.

struct ContentView: View {
@Environment(\.modelContext) private var context
@Query(sort: \Thing.name, order: .forward) var things: [Thing]
@State private var selectedThing: Thing?
var body: some View {
NavigationSplitView {
VStack {
Text("Some Things")
List(selection: $selectedThing) {
ForEach(things, id: \.self) { thing in
HStack {
Text(thing.name)
Text(thing.areYouSure.description)
}
}//for each
.onDelete{ indexSet in
indexSet.forEach { index in
if things[index] == selectedThing {
context.delete(things[index])
//this does not make any difference
do {
try context.save()
} catch {
print(error)
}
//this does not make any difference
//selectedThing = nil
}
}
}//on delete
}//list
}//v
.toolbar {
ToolbarItem(placement: .topBarTrailing) {
Button {
AddFourThings()
} label: {
Image(systemName: "plus")
}
}
}
} detail: {//nav split sidebar
ZStack {
if let selectedThing {
DetailView(thing: selectedThing)
} else {
Text("Choose a Thing")
}
}
}//nav split detail
}//body
private func AddFourThings() {
let thing1 = Thing(name: "Thing One", areYouSure: true)
let thing2 = Thing(name: "Thing Two", areYouSure: false)
let thing3 = Thing(name: "Thing Three", areYouSure: true)
let thing4 = Thing(name: "Thing Four", areYouSure: false)
context.insert(thing1)
context.insert(thing2)
context.insert(thing3)
context.insert(thing4)
}//add four
}//struct
struct DetailView: View {
@State private var isOn: Bool = false
var thing: Thing
var body: some View {
VStack {
Text(thing.name)
.font(.title)
Text(thing.areYouSure.description)
.font(.title)
Text(isOn.description)
.font(.title)
Toggle("Toggle Me", isOn: $isOn)
.font(.title)
}
}
}//detail view
@Model
class Thing: Identifiable {
var name: String
var areYouSure: Bool
init(name: String, areYouSure: Bool) {
self.name = name
self.areYouSure = areYouSure
}
}//class thing

Any guidance would be appreciated. Xcode 15.0 beta 4 (15A5195m), iOS 17

答案1

得分: 0

对于其他人来说,显然这是苹果已知的问题,并在发布说明中有提到(109838173)。建议的解决方法是在删除后明确保存,但对我来说仍然不起作用。在我的情况下,如果我删除.onDelete修饰符,而是在ForEach循环内添加一个滑动操作,那对我来说是可接受的。希望在测试版产品发布之前能解决这个问题。

ForEach(things, id: \.self) { thing in
    HStack {
        Text(thing.name)
        Text(thing.areYouSure.description)
    }
    .swipeActions(edge: .trailing) {
        Button(role: .destructive) {
            context.delete(thing)
            selectedThing = nil
            do {
                try context.save()
            } catch {
                print(error.localizedDescription)
            }
        } label: {
            Label("删除", systemImage: "trash")
        }
    }
}

祝好运。


<details>
<summary>英文:</summary>
For others. Apparently this is a known issue at Apple and is in the Release Notes (109838173). The suggested workaround is to explicitly save after the delete, however that still does not work for me. In my situation, if I remove the .onDelete modifier and instead add a swipe action inside the ForEach loop, that works for me and is acceptable. Hopefully the issue will be resolved before the Beta products are released.
ForEach(things, id: \.self) { thing in
HStack {
Text(thing.name)
Text(thing.areYouSure.description)
}
.swipeActions(edge: .trailing) {
Button(role: .destructive) {
context.delete(thing)
selectedThing = nil
do {
try context.save()
} catch {
print(error.localizedDescription)
}
} label: {
Label(&quot;Delete&quot;, systemImage: &quot;trash&quot;)
}
}
}//for each
Good Luck.
</details>

huangapple
  • 本文由 发表于 2023年8月5日 08:45:32
  • 转载请务必保留本文链接:https://go.coder-hub.com/76839740.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定