onAppear 不允许保存/更新选择器值的更改?
Posted
技术标签:
【中文标题】onAppear 不允许保存/更新选择器值的更改?【英文标题】:onAppear not allowing saving/updating change from picker value? 【发布时间】:2020-08-18 04:39:59 【问题描述】:我正在构建一个编辑视图,它允许用户更新列表项并将其保存回核心数据和列表。为此,我使用 .onAppear 操作将列表中的值传递到相应字段中。
所有数据都正确传递,切换和文本字段允许我轻松进行更改并将它们保存回核心数据并更新列表项。但是,如果我尝试更改选择器值 (emojiChoice) 并选择一个新值,则选择器值不会更改或保存回 Core Data。
当我注释掉选择器变量 (emojiChoice) 的 onAppear 操作时,选择器现在允许我选择我想要的值并将其保存回 Core Data。我还有另一个视图,它允许用户创建与此编辑视图几乎相同的项目,减去 onAppear 操作,它也可以工作。选择器允许用户选择和表情符号。因为有很多表情符号,所以我创建了一个数组,而只是将所选表情符号的数组索引作为 Int 传递。
如何解决此问题以允许选择器显示要编辑的值并允许对其进行更改?
这是编辑视图的代码:
struct editRemindr: View
@Environment(\.managedObjectContext) var moc
@Environment(\.presentationMode) var presentationMode
let emojiList = EmojiList()
@ObservedObject var reminder: ReminderEntity
@State private var showingDeleteAlert = false
// Form Variables
@State var notifyOn = true
@State var emojiChoice = 0
@State var notification: String
@State var notes: String
// Delete Reminder Function
func deleteAction()
moc.delete(reminder)
// try? self.moc.save()
presentationMode.wrappedValue.dismiss()
// View Controller
var body: some View
Form
// On/Off Toggle
Toggle(isOn: $notifyOn)
Text("On/Off")
// Emoji Picker
Picker(selection: $emojiChoice, label: Text("Emoji"))
ForEach(0 ..< emojiList.emojis.count)
Text(self.emojiList.emojis[$0])
// Notification Text
Section(header: Text("NOTIFICATION"))
HStack
TextField("Write your notification...", text: $notification)
.onReceive(notification.publisher.collect())
self.notification = String($0.prefix(60)) // <---- SET CHARACTER LIMIT
Text("\(notification.count) / 60")
.font(.caption)
.foregroundColor(.gray)
// Notes Text
Section(header: Text("NOTES"))
VStack
MultiLineTextField(text: $notes).frame(numLines: 6)
.padding(.top, 5)
.onReceive(notes.publisher.collect())
self.notes = String($0.prefix(240)) // <---- SET CHARACTER LIMIT
Text("\(notes.count) / 240")
.font(.caption)
.foregroundColor(.gray)
.frame(maxWidth: .infinity, alignment: .trailing)
// Save Changes Button
Section()
Button (action:
self.reminder.dateCreated = Date()
self.reminder.notifyOn = self.notifyOn
self.reminder.emojiChoice = Int64(self.emojiChoice)
self.reminder.notification = self.notification
self.reminder.notes = self.notes
try? self.moc.save()
self.presentationMode.wrappedValue.dismiss()
)
Text("SAVE CHANGES")
.fontWeight(.bold)
.foregroundColor(.white)
.font(.body)
.padding()
.frame(maxWidth: .infinity)
.background(Color.green)
.padding(.vertical, -6)
.padding(.horizontal, -15)
// Cancel Button
Button(action:
self.presentationMode.wrappedValue.dismiss()
)
Text("Cancel")
.frame(maxWidth: .infinity)
// Make List Items Appear in Fields
.onAppear(perform:
self.notifyOn = self.reminder.notifyOn
self.emojiChoice = Int(self.reminder.emojiChoice)
self.notification = self.reminder.notification ?? "unknown"
self.notes = self.reminder.notes ?? "unknown"
)
.alert(isPresented: $showingDeleteAlert)
Alert(title: Text("Delete Reminder"), message: Text("Are you sure you want to delete this Reminder?"), primaryButton: .destructive(Text("Delete"))
self.deleteAction()
, secondaryButton: .cancel()
)
.navigationBarTitle("Edit Reminder")
.navigationBarItems(trailing: Button(action: self.showingDeleteAlert = true
)
Image(systemName: "trash")
)
// Creates Text Limits
class TextLimit: ObservableObject
@Published var text = ""
didSet
if text.count > characterLimit && oldValue.count <= characterLimit
text = oldValue
let characterLimit: Int
init(limit: Int = 5)
characterLimit = limit
如果它也有帮助,这里是带有列表的内容视图的代码。
struct ContentView: View
@Environment(\.managedObjectContext) var moc
@FetchRequest(entity: ReminderEntity.entity(), sortDescriptors: [NSSortDescriptor(keyPath: \ReminderEntity.dateCreated, ascending: false)])
var reminder: FetchedResults<ReminderEntity>
@State private var showingAddScreen = false
@State var showWelcomeScreen = false
let emojiList = EmojiList()
//Toggle Control
@State var notifyOn = true
// Save Items Function
func saveItems()
do
try moc.save()
catch
print(error)
// Delete Item Function
func deleteItem(indexSet: IndexSet)
let source = indexSet.first!
let listItem = reminder[source]
moc.delete(listItem)
// View Controller
var body: some View
VStack
NavigationView
ZStack (alignment: .top)
// List View
List
ForEach(reminder, id: \.self) notification in
NavigationLink(destination: editRemindr(reminder: notification, notification: notification.notification ?? "unknown", notes: notification.notes ?? "unknown"))
// Text within List View
HStack
// MARK: TODO
// Toggle("NotifyOn", isOn: true)
// .labelsHidden() // Hides the label/title
Text("\(self.emojiList.emojis[Int(notification.emojiChoice)]) \(notification.notification!)")
.onDelete(perform: deleteItem)
// Navigation Items
.navigationBarTitle("", displayMode: .inline)
.navigationBarItems(
leading:
HStack
Button(action:
self.showWelcomeScreen.toggle()
)
Image(systemName: "info.circle.fill")
.font(.system(size: 24, weight: .regular))
.foregroundColor(.gray)
// Positioning Remindr Logo on Navigation
Image("remindrLogoSmall")
.resizable()
.aspectRatio(contentMode: .fit)
//.frame(width: 60, height: 60, alignment: .center)
.padding(.leading, 83)
.padding(.top, -10)
,
// Global Settings Navigation Item
trailing: NavigationLink(destination: globalSettings())
Image("settings")
.font(Font.title.weight(.ultraLight))
.foregroundColor(.gray)
)
// Add New Reminder Button
VStack
Spacer()
Button(action: self.showingAddScreen.toggle()
)
Image("addButton")
.renderingMode(.original)
.sheet(isPresented: $showingAddScreen)
newRemindr().environment(\.managedObjectContext, self.moc)
.sheet(isPresented: $showWelcomeScreen)
welcomeScreen()
【问题讨论】:
【参考方案1】:试试下面的
// Emoji Picker
Picker(selection: $emojiChoice, label: Text("Emoji"))
ForEach(0 ..< emojiList.emojis.count, id: \.self) // << added id !!
Text(self.emojiList.emojis[$0])
【讨论】:
谢谢,我试了一下,好像没什么效果。我验证删除 onAppear 操作允许我更改选择器值并将其保存回核心数据,但没有 onAppear 值不会通过核心数据的列表传递。切换和文本字段使用 onAppear 可以正常工作,但 Picker 似乎并非如此。我怀疑这是问题所在。有什么想法吗?【参考方案2】:我为选择器值创建了一个自定义绑定,它似乎可以解决问题。感谢Reddit user End3r117 为我指明了正确的方向!
// View Controller
var body: some View
let reminderChoice = Binding(
get: Int(self.reminder.emojiChoice) ,
set: self.reminder.emojiChoice = Int64($0)
)
return
Form
// On/Off Toggle
Toggle(isOn: $notifyOn)
Text("On/Off")
// Emoji Picker
Picker(selection: reminderChoice, label: Text("Emoji"))
ForEach(0 ..< self.emojiList.emojis.count, id: \.self)
Text(self.emojiList.emojis[$0])
【讨论】:
以上是关于onAppear 不允许保存/更新选择器值的更改?的主要内容,如果未能解决你的问题,请参考以下文章