核心数据对象仍然保存在presentationMode SwiftUI中的dismiss/cancel
Posted
技术标签:
【中文标题】核心数据对象仍然保存在presentationMode SwiftUI中的dismiss/cancel【英文标题】:Core Data Object still saved on dismiss/cancel in presentationMode SwiftUI 【发布时间】:2020-01-17 09:24:08 【问题描述】:当我尝试关闭/取消添加对象模式时,它正在创建一个空对象,而不是仅仅取消。
我已经尝试过 deleteObject、context.rollback() 和一堆其他随机的东西。希望得到一些帮助并能够回答任何问题。
通过将“取消”按钮放在 NavigationBarItem 中,我意识到这不是问题,但希望能够了解如何制作单独的“取消(或关闭)”按钮。
ContentView.swift
import SwiftUI
import CoreData
struct ContentView: View
@Environment(\.managedObjectContext) var moc
@FetchRequest(entity: Game.entity(), sortDescriptors: [NSSortDescriptor(keyPath: \Game.gameName, ascending: true)]) var games: FetchedResults<Game>
@State private var showingAddGame = false
var body: some View
GeometryReader geometry in
NavigationView
List
ForEach(self.games, id: \.self) games in
NavigationLink(destination: GameGoalsDetail(game: games))
VStack(alignment: .leading)
Text(games.gameName ?? "Unknown Game")
Text(games.gameDescription ?? "Unknown Game Description")
.onDelete(perform: self.removeGames)
.navigationBarItems(leading:
HStack
Button(action:
self.showingAddGame.toggle()
)
Text("Add Game")
.padding(.top, 50)
.foregroundColor(Color.yellow)
.sheet(isPresented: self.$showingAddGame)
AddGameView().environment(\.managedObjectContext, self.moc)
Image("Game Goals App Logo")
.resizable()
.frame(width: 100, height: 100)
.padding(.leading, (geometry.size.width / 2.0) + -160)
.padding(.bottom, -50)
, trailing:
EditButton()
.padding(.top, 50)
.foregroundColor(Color.yellow)
)
func removeGames(at offsets: IndexSet)
for index in offsets
let game = games[index]
moc.delete(game)
try? moc.save()
struct ContentView_Previews: PreviewProvider
static var previews: some View
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
let newGame = Game(context: context)
newGame.gameName = "Apex Legends"
newGame.gameDescription = "Maybe this will work"
return ContentView().environment(\.managedObjectContext, context)
AddGameView.swift
import SwiftUI
import CoreData
struct AddGameView: View
@Environment(\.managedObjectContext) var moc
@FetchRequest(entity: Game.entity(), sortDescriptors: []) var games: FetchedResults<Game>
@Environment(\.presentationMode) var presentationMode
@State private var gameName = ""
@State private var gameDescription = ""
@State private var showingAlert = false
var body: some View
Form
Section
TextField("Game Name", text: $gameName)
TextField("Game Description", text: $gameDescription)
HStack
Button("Add Game")
let newGame = Game(context: self.moc)
newGame.gameName = self.gameName
newGame.gameDescription = self.gameDescription
do
try self.moc.save()
self.presentationMode.wrappedValue.dismiss()
catch
print("Whoops! \(error.localizedDescription)")
Button(action:
self.presentationMode.wrappedValue.dismiss()
)
Text("Cancel")
.padding(10)
.foregroundColor(Color.white)
.background(Color.red)
struct AddGameView_Previews: PreviewProvider
static var previews: some View
AddGameView()
我已经搜索过所有内容,所以如果我在 *** 帖子中遗漏了一些内容,请将其链接起来,因为我不仅想解决这个问题,还想了解原因。
【问题讨论】:
【参考方案1】:您的取消按钮未创建空对象。问题是表单中包含“添加”和“取消”按钮的整行是交互式的,并且会触发两个按钮的操作。
我在这里找到了答案:https://***.com/a/59402642/12315994 要保持当前布局,您只需为每个按钮添加一行:
.buttonStyle(BorderlessButtonStyle())
在此之后,只有点击每个按钮才会触发动作。带有按钮的表单行将不可点击。
还有 2 个其他解决方案。两者都是为了将您的按钮移出表单。
解决方案 1 是像这样将按钮移动到 NavigationBarItems:
导入 SwiftUI 导入核心数据
struct AddGameView: View
@Environment(\.managedObjectContext) var moc
@FetchRequest(entity: Game.entity(), sortDescriptors: []) var games: FetchedResults<Game>
@Environment(\.presentationMode) var presentationMode
@State private var gameName = ""
@State private var gameDescription = ""
@State private var showingAlert = false
var body: some View
NavigationView
VStack
Form
Section
TextField("Game Name", text: $gameName)
TextField("Game Description", text: $gameDescription)
.navigationBarItems(
leading:
Button(action:
self.presentationMode.wrappedValue.dismiss()
)
Text("Cancel")
.padding(10)
.foregroundColor(Color.white)
.background(Color.red)
,
trailing:
Button(action:
let newGame = Game(context: self.moc)
newGame.gameName = self.gameName
newGame.gameDescription = self.gameDescription
do
try self.moc.save()
self.presentationMode.wrappedValue.dismiss()
catch
print("Whoops! \(error.localizedDescription)")
)
Text("Add Game")
)
解决方案 2 是将按钮移出Form并将它们移动到屏幕底部。像这样:
import SwiftUI
import CoreData
struct AddGameView: View
@Environment(\.managedObjectContext) var moc
@FetchRequest(entity: Game.entity(), sortDescriptors: []) var games: FetchedResults<Game>
@Environment(\.presentationMode) var presentationMode
@State private var gameName = ""
@State private var gameDescription = ""
@State private var showingAlert = false
var body: some View
VStack
Form
Section
TextField("Game Name", text: $gameName)
TextField("Game Description", text: $gameDescription)
HStack
Button(action:
let newGame = Game(context: self.moc)
newGame.gameName = self.gameName
newGame.gameDescription = self.gameDescription
do
try self.moc.save()
self.presentationMode.wrappedValue.dismiss()
catch
print("Whoops! \(error.localizedDescription)")
)
Text("Add Game")
Button(action:
self.presentationMode.wrappedValue.dismiss()
)
Text("Cancel")
.padding(10)
.foregroundColor(Color.white)
.background(Color.red)
从用户体验的角度来看,这两个选项都比您当前的布局更好,因为按钮现在位于更标准的位置。尤其是版本 1 是在 ios 中呈现此类按钮的更标准方式。
【讨论】:
以上是关于核心数据对象仍然保存在presentationMode SwiftUI中的dismiss/cancel的主要内容,如果未能解决你的问题,请参考以下文章