SwiftUI 2.0 / CoreData 2021:没有错误但实体未保存
Posted
技术标签:
【中文标题】SwiftUI 2.0 / CoreData 2021:没有错误但实体未保存【英文标题】:SwiftUI 2.0 / CoreData 2021: No error but entity not saved 【发布时间】:2021-02-24 09:37:02 【问题描述】:我有一个 SwiftUI 2.0 应用程序,它使用 CoreData 在本地存储数据,虽然当我尝试在版本视图中将数据保存到 CoreData 时,preview
模式可以将数据写入内存或不写入内存(我测试了两者),但我没有收到错误消息,但数据没有写入模拟器的 sqlite 数据文件......我做错了什么?
我有 2 个实体处于一对多关系中:
发帖:
日期:日期 id:UUID 文本:字符串 时间戳:日期 图片:toMany 关系 / 目的地 PostPic / 反向帖子PostPic:
数据:BinaryData / 允许外部存储 post:toOne 关系 / 目的地 Post / 反向图片我已提取以下主要文件:
MyApp.swift
import SwiftUI
@main
struct MyApp: App
let persistenceController = PersistenceController.shared
var body: some Scene
WindowGroup
MyNavigationView().environment(\.managedObjectContext, persistenceController.container.viewContext)
Persistence.swift
import Foundation
import SwiftUI
import CoreData
import CloudKit
struct PersistenceController
static let shared = PersistenceController()
static var preview: PersistenceController =
let result = PersistenceController(inMemory: true)
let viewContext = result.container.viewContext
for day in 1...10
let newPost = Post(context: viewContext)
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy/MM/dd"
newPost.date = dateFormatter.date(from: "2021/02/\(String(format: "%02d", day))")!
newPost.id = UUID()
newPost.text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
newpost.timestamp = Date()
for index in 1...7
let newPostPic = PostPic(context: viewContext)
if let image = UIImage(named:newPostPic.filename!)
newPostPic.data = image.pngData()
newPost.addToFiles(newPostPic)
do
try viewContext.save()
catch
// Replace this implementation with code to handle the error appropriately.
// fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
let nsError = error as NSError
fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
return result
()
let container: NSPersistentCloudKitContainer
private static var _model: NSManagedObjectModel?
private static func model(name: String) throws -> NSManagedObjectModel
if _model == nil
_model = try loadModel(name: name, bundle: Bundle.main)
return _model!
private static func loadModel(name: String, bundle: Bundle) throws -> NSManagedObjectModel
guard let modelURL = bundle.url(forResource: name, withExtension: "momd") else
throw CoreDataError.modelURLNotFound(forResourceName: name)
guard let model = NSManagedObjectModel(contentsOf: modelURL) else
throw CoreDataError.modelLoadingFailed(forURL: modelURL)
return model
enum CoreDataError: Error
case modelURLNotFound(forResourceName: String)
case modelLoadingFailed(forURL: URL)
init(inMemory: Bool = false)
container = NSPersistentCloudKitContainer(name: "curum")
if inMemory
container.persistentStoreDescriptions.first!.url = URL(fileURLWithPath: "/dev/null")
container.loadPersistentStores(completionHandler: (storeDescription, error) in
if let error = error as NSError?
fatalError("Unresolved error \(error), \(error.userInfo)")
)
MyNavigationView.swift
struct MyNavigationView: View
@Environment(\.managedObjectContext) private var viewContext
var body: some View
NavigationView
TabView // tab bar at the bottom of the screen
HomeView()
.tabItem
Image(systemName: "house.fill")
.tag(0)
.navigationBarTitleDisplayMode(.inline)
.navigationTitle("MyApp")
struct MyNavigationView_Previews: PreviewProvider
static var previews: some View
MyNavigationView()
HomeView.swift
//
// HomeView.swift
// curum
//
// Created by loic on 2021/02/19.
//
import SwiftUI
struct HomeView: View
var body: some View
ZStack
// ...
VStack // the plus button
Spacer()
HStack
Spacer()
NavigationLink(destination: EditionView().environment(\.managedObjectContext, PersistenceController.preview.container.viewContext))
ZStack
Circle()
.frame(width: 80, height: 80)
Image(systemName: "plus")
.renderingMode(.template)
.font(.system(size: 60, weight: .light))
.padding(.trailing, 16)
.padding(.bottom, 16)
struct HomeView_Previews: PreviewProvider
static var previews: some View
HomeView().environment(\.managedObjectContext, PersistenceController.preview.container.viewContext)
EditionView.swift
import Foundation
import SwiftUI
import CoreData
struct EditionView: View
@Environment(\.managedObjectContext) private var viewContext
@Environment(\.presentationMode) var mode: Binding<PresentationMode>
@State private var postText: String = ""
@State private var postImage: Image = Image("image1")
@State private var showingImagePicker = false
@State private var inputImage: UIImage?
var body: some View
VStack
TextEditor(text: $postText)
.lineSpacing(10)
.border(Color.gray)
.padding(.all)
HStack
Button(action:
self.showingImagePicker = true
)
if (inputImage == nil)
Text("Pick Image")
else
postImage
.resizable()
.renderingMode(.original)
.frame(width: 100, height: 100)
.sheet(isPresented: $showingImagePicker, onDismiss: loadImage)
ImagePicker(image: self.$inputImage)
.navigationBarBackButtonHidden(true)
.navigationBarItems(leading: Button(action :
self.mode.wrappedValue.dismiss()
)
Image(systemName: "xmark")
,
trailing: Button
let newPost = Post(use: viewContext)
newPost.date = Date()
newPost.id = UUID()
newPost.text = entryText
newPost.timestamp = Date()
let newPostPic = PostPic(use: viewContext)
newPostPic.data = inputImage!.pngData()
newPost.addToFiles(newPostPic)
do
try viewContext.save()
mode.wrappedValue.dismiss()
catch
let nsError = error as NSError
fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
label:
Image(systemName: "checkmark.circle.fill")
)
func loadImage()
guard let inputImage = inputImage else return
postImage = Image(uiImage: inputImage)
struct EditionView_Previews: PreviewProvider
static var previews: some View
EditionView()
struct ImagePicker: UIViewControllerRepresentable
@Environment(\.presentationMode) var presentationMode
@Binding var image: UIImage?
class Coordinator: NSObject, UINavigationControllerDelegate, UIImagePickerControllerDelegate
let parent: ImagePicker
init(_ parent: ImagePicker)
self.parent = parent
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any])
if let uiImage = info[.originalImage] as? UIImage
parent.image = uiImage
parent.presentationMode.wrappedValue.dismiss()
func makeCoordinator() -> Coordinator
Coordinator(self)
func makeUIViewController(context: UIViewControllerRepresentableContext<ImagePicker>) -> UIImagePickerController
let picker = UIImagePickerController()
picker.delegate = context.coordinator
return picker
func updateUIViewController(_ uiViewController: UIImagePickerController, context: UIViewControllerRepresentableContext<ImagePicker>)
** 编辑以回应@Tushar Sharma**
我忘了补充一下,我在NSManagedObject
中添加了以下扩展名,以消除Multiple NSEntityDescriptions Claim NSManagedObject Subclass 中的错误:
import Foundation
import CoreData
public extension NSManagedObject
convenience init(use context: NSManagedObjectContext)
let name = String(describing: type(of: self))
let entity = NSEntityDescription.entity(forEntityName: name, in: context)!
self.init(entity: entity, insertInto: context)
【问题讨论】:
不确定实体的初始化器是否应该看起来像“let newPost = Post(context: viewContext)?” 我遇到了一个错误,我通过在***.com/questions/51851485/… 中向 NSManagedObject 添加扩展名解决了这个错误,我在问题的末尾添加了信息 【参考方案1】:抱歉,这是 HomeView.swift 文件中的简单复制粘贴问题:
在下一行,我使用了 preview 持久化上下文 ...
NavigationLink(destination: EditionView().environment(\.managedObjectContext, PersistenceController.preview.container.viewContext))
...而不是使用共享:
NavigationLink(destination: EditionView().environment(\.managedObjectContext, PersistenceController.shared.container.viewContext))
这解决了我的问题!
【讨论】:
以上是关于SwiftUI 2.0 / CoreData 2021:没有错误但实体未保存的主要内容,如果未能解决你的问题,请参考以下文章
SwiftUI 2.0列表项层级缩进显示CoreData托管数据的3种实现
Xcode 12.2+生成SwiftUI 2.0 CoreData模板预览时崩溃问题的解决
Xcode 12.2+生成SwiftUI 2.0 CoreData模板预览时崩溃问题的解决