如何在 SwiftUI 中读出 Indexset 元素的值?
How to read out values of Indexset elements in SwiftUI?
我有一个非常简单的 ForEach List 并且使用 onDelete() 删除条目没有问题。但是,由于元素中的一个变量存储了文件的 url,我不想留下它,所以我希望通过 FileManager 实现清理。但对于我来说,我似乎无法访问实际的 url 以插入 FileManager 操作。
这是我得到的,以及相关的错误:
struct ListItem: Identifiable, Codable {
let id = UUID()
let name: String
let fileurl: URL
}
class ItemList: ObservableObject {
@Published var items: [ListItem] {
didSet {
let encoder = JSONEncoder()
if let encoded = try? encoder.encode(items) {
UserDefaults.standard.set(encoded, forKey: "Items")
}
}
}
init() {
if let items = UserDefaults.standard.data(forKey: "Items") {
let decoder = JSONDecoder()
if let decoded = try? decoder.decode([ListItem].self, from: items) {
self.items = decoded
return
}
}
self.items = []
}
}
struct ItemListView: View {
func getDocumentsDirectory() -> URL {
return FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask).first!
}
@ObservedObject var itemlist = ItemList()
var supportFolder: URL {
return FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask).first!
}
@EnvironmentObject var thingy: Thingy
var body: some View {
VStack {
Spacer()
Spacer()
Spacer()
List {
ForEach(itemlist.items) { item in
HStack {
VStack(alignment: .leading) {
Text(item.name)
.font(.headline)
Text(item.fileurl.lastPathComponent)
}
.onTapGesture {
self.thingy.load(self.supportFolder.appendingPathComponent("/listfiles/\(item.fileurl.lastPathComponent)")) //No issues with item.fileurl here
print("Selected: \(item.fileurl)")
}
}
}
.onDelete(perform: removeItems)
}.disabled(keyMissing)
.navigationBarTitle("List files", displayMode: .large).accentColor(Color.blue)
.navigationBarItems(trailing:
Button(action: {
…
}
) {NavigationLink(…) {
Image(systemName: "plus")
}
}
)
Button(…){…}
}
.onAppear(perform: {…})
.onDisappear(…)
}
// MARK: below is the issue
func removeItems(at offsets: IndexSet) {
do {
try FileManager.default.removeItem(atPath: (itemlist.items.fileurl).path)
print("File is deleted")
}
catch { print("Couldn't delete file")} //This would be ideal, but doesn't work stating "Value of type '[ListItem]' has no member 'fileurl'"
itemlist.items.remove(atOffsets: offsets) //This works fine
}
}
理想情况下,我可以简单地插入项目 list.items.fileurl
但它的行为就像是未知的。
我也尝试过使用 list.items.description
(和类似的)做一个巨大的解决方法,但是没有一致的方法来始终如一地提取输出字符串的正确部分。老实说,我感觉很奇怪,我无法访问文件 url 的值,我觉得我正盯着解决方案的脸看,但看不到它。
我也尝试简单地应用 onDelete()
中的逻辑
像这样:
.onDelete{
do {
try FileManager.default.removeItem(atPath: (binlist.items.fileloc).path)
print("File is deleted")
}
catch { print("Couldn't delete file")}
}
但是这让我感到 Cannot convert value of type '() -> ()' to expected argument type 'Optional<(IndexSet) -> Void>'
我觉得这里有点格格不入,找不到这方面的好文档。
编辑:@Asperi 的解决方案对我有用,不敢相信我在发布之前就在盯着解决方案。
可以像下面这样
func removeItems(at offsets: IndexSet) {
for i in offsets {
do {
try FileManager.default.removeItem(atPath: (itemlist.items[i].fileurl).path)
print("File is deleted")
}
catch { print("Couldn't delete file")}
}
itemlist.items.remove(atOffsets: offsets) //This works fine
}
我有一个非常简单的 ForEach List 并且使用 onDelete() 删除条目没有问题。但是,由于元素中的一个变量存储了文件的 url,我不想留下它,所以我希望通过 FileManager 实现清理。但对于我来说,我似乎无法访问实际的 url 以插入 FileManager 操作。
这是我得到的,以及相关的错误:
struct ListItem: Identifiable, Codable {
let id = UUID()
let name: String
let fileurl: URL
}
class ItemList: ObservableObject {
@Published var items: [ListItem] {
didSet {
let encoder = JSONEncoder()
if let encoded = try? encoder.encode(items) {
UserDefaults.standard.set(encoded, forKey: "Items")
}
}
}
init() {
if let items = UserDefaults.standard.data(forKey: "Items") {
let decoder = JSONDecoder()
if let decoded = try? decoder.decode([ListItem].self, from: items) {
self.items = decoded
return
}
}
self.items = []
}
}
struct ItemListView: View {
func getDocumentsDirectory() -> URL {
return FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask).first!
}
@ObservedObject var itemlist = ItemList()
var supportFolder: URL {
return FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask).first!
}
@EnvironmentObject var thingy: Thingy
var body: some View {
VStack {
Spacer()
Spacer()
Spacer()
List {
ForEach(itemlist.items) { item in
HStack {
VStack(alignment: .leading) {
Text(item.name)
.font(.headline)
Text(item.fileurl.lastPathComponent)
}
.onTapGesture {
self.thingy.load(self.supportFolder.appendingPathComponent("/listfiles/\(item.fileurl.lastPathComponent)")) //No issues with item.fileurl here
print("Selected: \(item.fileurl)")
}
}
}
.onDelete(perform: removeItems)
}.disabled(keyMissing)
.navigationBarTitle("List files", displayMode: .large).accentColor(Color.blue)
.navigationBarItems(trailing:
Button(action: {
…
}
) {NavigationLink(…) {
Image(systemName: "plus")
}
}
)
Button(…){…}
}
.onAppear(perform: {…})
.onDisappear(…)
}
// MARK: below is the issue
func removeItems(at offsets: IndexSet) {
do {
try FileManager.default.removeItem(atPath: (itemlist.items.fileurl).path)
print("File is deleted")
}
catch { print("Couldn't delete file")} //This would be ideal, but doesn't work stating "Value of type '[ListItem]' has no member 'fileurl'"
itemlist.items.remove(atOffsets: offsets) //This works fine
}
}
理想情况下,我可以简单地插入项目 list.items.fileurl
但它的行为就像是未知的。
我也尝试过使用 list.items.description
(和类似的)做一个巨大的解决方法,但是没有一致的方法来始终如一地提取输出字符串的正确部分。老实说,我感觉很奇怪,我无法访问文件 url 的值,我觉得我正盯着解决方案的脸看,但看不到它。
我也尝试简单地应用 onDelete()
像这样:
.onDelete{
do {
try FileManager.default.removeItem(atPath: (binlist.items.fileloc).path)
print("File is deleted")
}
catch { print("Couldn't delete file")}
}
但是这让我感到 Cannot convert value of type '() -> ()' to expected argument type 'Optional<(IndexSet) -> Void>'
我觉得这里有点格格不入,找不到这方面的好文档。
编辑:@Asperi 的解决方案对我有用,不敢相信我在发布之前就在盯着解决方案。
可以像下面这样
func removeItems(at offsets: IndexSet) {
for i in offsets {
do {
try FileManager.default.removeItem(atPath: (itemlist.items[i].fileurl).path)
print("File is deleted")
}
catch { print("Couldn't delete file")}
}
itemlist.items.remove(atOffsets: offsets) //This works fine
}