【发布时间】:2020-09-13 15:18:49
【问题描述】:
我希望以编程方式从 SwiftUI 列表数据源中删除一条记录,当我检测到 onAppear 该列表有一条陈旧的记录时,该记录在用户离开列表屏幕时得到更新。
例如,用户在项目编辑屏幕上。此屏幕标记 Environment 对象中的一个属性,该属性与更新的记录有关,以便 List 屏幕可以使用此属性在 List 再次出现时从 List 数据源中删除过时的记录。希望这种刷新 List 的模式可以吗?
List{
Section{
Toggle(isOn: self.$showArchivedItems.onChange(showOptionsChanged)) {
Text("Show Archived Records).font(.headline)
}
}
Section {
ForEach(userData.items) { dataItem in
NavigationLink(destination: ItemDetailView(item: dataItem)){
ListRowItemView(item: dataItem)
}
}.onDelete(perform: self.onDeletingItems)
.onAppear() {
if let updatedRecord = self.userData.lastUpdatedRecord {
if let updatedRecordId = self.userData.items.firstIndex(where: {return $0.id == updatedRecord.id}) {
//OPTION #1 - Doesn’t work
//self.userData.items.remove(at: updatedRecordId)
//self.userData.items.append(updatedRecord)
//OPTION #2 - Doesn’t work
//self.userData.items.replaceSubrange(updatedRecordId... updatedRecordId, with: [updatedRecord])
//OPTION #3 - works
self.userData.items = self.storage.load()
}
}
}
}
}.listStyle(GroupedListStyle())
private func onDeletingItems(indexset: IndexSet) {
var itemsToDeactivate: [ItemModel] = []
for index in indexset {
userData.items[index].isArchived = true
itemsToDeactivate.append(userData.items[index])
}
for item in itemsToDeactivate {
storage.persist(dataItem: item)
}
userData.items.remove(atOffsets: indexset)
}
附加代码:
UserData.swift
import Foundation
final class UserData: ObservableObject {
@Published var items: [ItemModel]
var lastUpdatedRecord: ItemModel? = nil
init(data: [ItemModel] = []) {
self.items = data
}
func clearLastUpdatedRecord() {
self.lastUpdatedRecord = nil
}
}
列表视图
struct ListView: View {
@EnvironmentObject var userData: UserData
var body: some View {
NavigationView {
VStack{
List{
//ForEach on userData.items
}
}
}
}
SceneDelegate.swift
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
// Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
// If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
// This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
// Create the SwiftUI view that provides the window contents.
let storage = ItemLocalStorage()
let userData = UserData(data: storage.load())
let userSettings = SettingsModel()
let contentView = ContentView().environmentObject(storage).environmentObject(userData).environmentObject(userSettings)
// Use a UIHostingController as window root view controller.
if let windowScene = scene as? UIWindowScene {
let window = UIWindow(windowScene: windowScene)
window.rootViewController = UIHostingController(rootView: contentView)
self.window = window
window.makeKeyAndVisible()
}
}
问题是我尝试了两个选项来专门从列表数据源中删除过时的记录,方法是找到它的索引(在选项#1中)并附加更新的实例,或者在选项#2中我试图用更新的替换过时的记录实例。
在这两个选项中,更新的记录确实会添加到列表中,但过时的记录不会从列表中删除,尽管过时的记录已经更新了数据,但我看到了更新记录的双重实例。
当我从存储中完全刷新数据源(选项# 3)时,列表会显示正确的项目,即只有一个更新记录的实例。
任何人都可以建议如何以编程方式从列表数据源中删除记录,以便列表也刷新其视图。我的意思是我不必再次从存储中加载所有记录来更新列表,因为单个记录已更新。 (在我的应用程序中,更新是用户触发的,一次只能更新一条记录,根据当前设计)
我还想知道,List 确实支持编辑 List 中的项目,就像我在 List 上实现了 onDelete 一样。在这里,用户可以将 List 置于 editMode 并删除单个项目。我确信 List 没有调用我的存储来提取所有数据。那么 List 是如何管理删除单个项目并刷新其显示的呢?
【问题讨论】:
-
只需从
userData.items中删除元素 -
我已经在 OPTION#1 中这样做了,但它没有从列表显示中删除。列表继续显示项目
-
你会显示
userData类型的代码吗? -
添加了 userData 的代码和其他一些代码
-
您的
ItemModel类型是否有唯一的 id 字段?喜欢UUID?
标签: swiftui swiftui-list