在swiftUI中创建可编辑对象的动态列表,并将其存储在手机中
我试图在SwiftUI中创建一个可编辑对象列表。这是我的想法 首先,可编辑项如下:在swiftUI中创建可编辑对象的动态列表,并将其存储在手机中,swift,swiftui,Swift,Swiftui,我试图在SwiftUI中创建一个可编辑对象列表。这是我的想法 首先,可编辑项如下: struct Item: Identifiable { var id: UUID var ItemNum: Int var notes: String = "" } final class ItemStore: ObservableObject { @Published var items: [Item] = [ .init(id: .init(
struct Item: Identifiable {
var id: UUID
var ItemNum: Int
var notes: String = ""
}
final class ItemStore: ObservableObject {
@Published var items: [Item] = [
.init(id: .init(), ItemNum: 55),
.init(id: .init(), ItemNum: 57),
.init(id: .init(), ItemNum: 87)
]
}
之后,我创建了一个从ItemStore获取数据的列表:
struct ItemView: View {
@State private var editMode = EditMode.inactive
@ObservedObject var store: ItemStore
var body: some View {
NavigationView {
List {
ForEach(store.items.indexed(), id:\.1.id) {index, item in
NavigationLink(destination: ItemEditingView(item: self.$store.items[index])) {
VStack(alignment: .leading) {
Text("Item Num: \(item.itemNum)")
}
}
}
}
//.onAppear(perform: store.fetch) // want to fetch the data from the store whenever the list appear, however, no idea to perform the function?!
.navigationBarTitle("Items")
.navigationBarItems( trailing: addButton)
.environment(\.editMode, $editMode)
}
}
private var addButton: some View {
switch editMode {
case .inactive:
return AnyView(Button(action: onAdd) { Image(systemName: "plus") })
default:
return AnyView(EmptyView())
}
}
private func onAdd() {
store.items.append(Item(id: UUID(), itemNum: 10))
}
}
编辑视图:
struct ItemEditingView: View {
@Environment(\.presentationMode) var presentation
@Binding var item: Item
var body: some View {
Form {
Section(header: Text("Item")) {
Text(Text("Item Num: \(item.itemNum)"))
TextField("Type something...", text: $item.notes)
}
Section {
Button("Save") {
self.presentation.wrappedValue.dismiss()
}
}
}.navigationTitle(Text("Item Num: \(item.itemNum)"))
}
}
我的问题是:
首先是您的第二个问题:在存储(持久化数据)方面,您有很多选择。最简单的方法是将其存储在
UserDefaults
中,我将在示例中展示。您还可以选择使用CoreData,这将是一个更需要设置的过程,但稍后将为您提供更健壮的解决方案。还有更多的选项,如领域、Firebase、SQLite等
struct Item: Identifiable, Codable {
var id: UUID = UUID()
var itemNum: Int
var notes: String = ""
}
final class ItemStore: ObservableObject {
@Published var items: [Item] = [] {
didSet {
let encoder = JSONEncoder()
if let encoded = try? encoder.encode(items) {
UserDefaults.standard.set(encoded, forKey: "savedItems")
}
}
}
let defaultValues : [Item] = [
.init(itemNum: 55),
.init(itemNum: 57),
.init(itemNum: 87)
]
func fetch() {
let decoder = JSONDecoder()
if let savedItems = UserDefaults.standard.object(forKey: "savedItems") as? Data,
let loadedItems = try? decoder.decode([Item].self, from: savedItems) {
items = loadedItems
} else {
items = defaultValues
}
}
}
struct ContentView : View {
@State private var editMode = EditMode.inactive
@ObservedObject var store: ItemStore = ItemStore()
var body: some View {
NavigationView {
List {
ForEach(Array(store.items.enumerated()), id:\.1.id) { (index,item) in
NavigationLink(destination: ItemEditingView(item: self.$store.items[index])) {
VStack(alignment: .leading) {
Text("Item Num: \(item.itemNum)")
}
}
}
}
.onAppear(perform: store.fetch)
.navigationBarTitle("Items")
.navigationBarItems( trailing: addButton)
.environment(\.editMode, $editMode)
}
}
private var addButton: some View {
switch editMode {
case .inactive:
return AnyView(Button(action: onAdd) { Image(systemName: "plus") })
default:
return AnyView(EmptyView())
}
}
private func onAdd() {
store.items.append(Item(id: UUID(), itemNum: 10))
}
}
struct ItemEditingView: View {
@Environment(\.presentationMode) var presentation
@Binding var item: Item
var body: some View {
Form {
Section(header: Text("Item")) {
Text("Item Num: \(item.itemNum)")
TextField("Type something...", text: $item.notes)
}
Section {
Button("Save") {
self.presentation.wrappedValue.dismiss()
}
}
}.navigationTitle(Text("Item Num: \(item.itemNum)"))
}
}
关于第一个问题,fetch
失败的原因是您没有fetch
方法。另外,由于每次创建ItemStore
时才填充items
数组,因此没有任何东西可获取
注:
Item
现在符合Codable
——这就是允许它转换为可以从UserDefaults保存/加载的值的原因fetch
现在在appear上调用didSet
,将新数据保存到UserDefaults枚举的
而不是ForEach
中的索引的
,不调用文本(文本(
带有嵌套值,使用整个itemNum
的相同大小写,等等重要信息:测试此功能时,请确保在更改后几秒钟将数据保存到UserDefaults中,然后关闭应用程序并再次打开它。第二点取决于您的选择,如果您的数据存储很大(不是很大),Personal和have relationships,选项是使用CoreData,但如果您想要类似于UserDefault的功能,并且数据不是个人的,则swiftUI将提供@AppStorage属性。