swiftui 如何从详细信息到编辑视图获取核心数据值

2024-02-28

通过使用核心数据构建应用程序来学习 swiftui;陷入AddEdit的Detail到Edit的数据流向问题;从 AddEdit 到 List 以及从 List 到 Detail 的流程都可以。在网上搜索但没有找到有用的信息或者我不明白。这是该问题的一个简化项目。它在 13.2 beta 上兼容并可在模拟器上运行,但存在详细信息中的空白编辑视图问题。

views:

struct FileList: View {

    @FetchRequest(sortDescriptors: [ NSSortDescriptor(keyPath: \Item.fileName, ascending: false) ], animation: .default) var items: FetchedResults<Item>
    @State private var showAdd = false

    var body: some View {
        NavigationView {
            List {
                ForEach(items) { item in
                    NavigationLink(destination: FileDetail(item: item)) {
                        Text(item.fileName ?? "").font(.headline)
                    }
                }
            }
            .navigationTitle("List")
            .navigationBarItems(trailing: Button(action: {
                showAdd = true
            }, label: { Image(systemName: "plus.circle")
            })
            .sheet(isPresented: $showAdd) {
                FileAddEdit(items: VM())
            }
            )
        }
    }
}

struct FileList_Previews: PreviewProvider {
    static let context = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)
    static var previews: some View {
        FileList()
    }
}

struct FileDetail: View {
     
    @Environment(\.managedObjectContext) var context
    @Environment(\.presentationMode) var presentationMode
    @State var showingEdit = false
    @ObservedObject var item: Item

    var body: some View {
        VStack {
            Form {
                Text(self.item.fileName ?? "File Name")
                Button(action: {
                    showingEdit.toggle()
                }, label: {
                    title: do { Text("Edit")
                    }
                })
                .sheet(isPresented: $showingEdit) {
                    FileAddEdit(items: VM())
                }
            }
        }.navigationTitle("Detail")
    }
}

struct FileDetails_Previews: PreviewProvider {
    static let moc = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)
    static var previews: some View {
        let item = Item(context: moc)
        return NavigationView {
            FileDetail(item: item)
        }
    }
}

struct FileAddEdit: View {
    
    @Environment(\.managedObjectContext) var moc
    @ObservedObject var items = VM()
    
    var body: some View {
        NavigationView {
            VStack {
                Form {
                    TextField("File Name", text: $items.fileName)
                    Button(action: {
                        items.writeData(context: moc)
                    }, label: {
                    title: do { Text(items.updateFile == nil ? "Add" : "Edit")
                    }})
                }
            }
            .navigationTitle("\(items.updateFile == nil ? "Add" : "Edit")")
        }
    }
}

struct FileAddEdit_Previews: PreviewProvider {
    static var previews: some View {
        FileAddEdit(items: VM())
    }
}

VM:

class VM: ObservableObject {
    @Published var fileName = ""
    @Published var id = UUID()
    @Published var isNewData = false
    @Published var updateFile : Item!
    
    init() {
    }
    
    var temporaryStorage: [String] = []

    func writeData(context : NSManagedObjectContext) {
        if updateFile != nil {
            updateCurrentFile()
        } else {
            createNewFile(context: context)
        }
        do {
            try context.save()
        } catch {
            print(error.localizedDescription)
        }
    }
    
    func DetailItem(fileItem: Item){
        fileName = fileItem.fileName ?? ""
        id = fileItem.id ?? UUID()
        updateFile = fileItem
    }
    
    func EditItem(fileItem: Item){
        fileName = fileItem.fileName ?? ""
        id = fileItem.id ?? UUID()
        isNewData.toggle()
        updateFile = fileItem
    }
    
    private func createNewFile(context : NSManagedObjectContext) {
        let newFile = Item(context: context)
        newFile.fileName = fileName
        newFile.id = id
    }
    
    private func updateCurrentFile() {
        updateFile.fileName = fileName
        updateFile.id = id
    }
    
    private func resetData() {
        fileName = ""
        id = UUID()
        isNewData.toggle()
        updateFile = nil
    }
}

非常感谢您的时间和建议!


下面是我制作的一个工作示例,它扩展了默认的 Core Data SwiftUI 应用程序模板,以在工作表中添加项目时间戳的编辑。该工作表在子上下文中加载该项目,以便可以进行编辑,如果取消,编辑将被丢弃,但如果保存,则更改将被推送到视图上下文中并保存。如果您不熟悉用于编辑的子上下文,我推荐 Apple 的旧版本CoreDataBooks 示例项目 https://developer.apple.com/library/archive/samplecode/CoreDataBooks/Introduction/Intro.html#//apple_ref/doc/uid/DTS40008405.

您需要知道的主要事情是,当我们使用工作表来编辑某些内容时,我们使用的版本采用的是项目而不是布尔值。这允许您正确配置编辑视图。

    import SwiftUI
    import CoreData
    
    struct ItemEditorConfig: Identifiable {
        let id = UUID()
        let context: NSManagedObjectContext
        let item: Item
        
        init(viewContext: NSManagedObjectContext, objectID: NSManagedObjectID) {
            // create the scratch pad context
            context = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)
            context.parent = viewContext
            // load the item into the scratch pad
            item = context.object(with: objectID) as! Item
        }
    }
    
    struct ItemEditor: View {
        @ObservedObject var item: Item // this is the scratch pad item
        @Environment(\.managedObjectContext) private var context
        @Environment(\.dismiss) private var dismiss
        let onSave: () -> Void
        @State var errorMessage: String?
        
        var body: some View {
            NavigationView {
                Form {
                    Text(item.timestamp!, formatter: itemFormatter)
                    if let errorMessage = errorMessage {
                        Text(errorMessage)
                    }
                    Button("Update Time") {
                        item.timestamp = Date()
                    }
                }
                .toolbar {
                    ToolbarItem(placement: .navigationBarLeading) {
                        Button("Cancel") {
                            dismiss()
                        }
                    }
                    ToolbarItem(placement: .navigationBarTrailing) {
                        Button("Save") {
                            // first save the scratch pad context then call the handler which will save the view context.
                            do {
                                try context.save()
                                errorMessage = nil
                                onSave()
                            } catch {
                                let nsError = error as NSError
                                errorMessage  = "Unresolved error \(nsError), \(nsError.userInfo)"
                            }
                        }
                    }
                }
            }
        }
    }
    
    
    struct DetailView: View {
        @Environment(\.managedObjectContext) private var viewContext
        @ObservedObject var item: Item
        @State var itemEditorConfig: ItemEditorConfig?
        
        var body: some View {
            
            Text("Item at \(item.timestamp!, formatter: itemFormatter)")
                .toolbar {
                    ToolbarItem(placement: .navigationBarTrailing) {
                        Button(action: edit) {
                            Text("Edit")
                        }
                    }
                }
                .sheet(item: $itemEditorConfig, onDismiss: didDismiss) { config in
                    ItemEditor(item: config.item) {
                        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)")
                        }
                        itemEditorConfig = nil
                    }
                    .environment(\.managedObjectContext, si.context)
                }
        }
        
        func edit() {
            itemEditorConfig = ItemEditorConfig(viewContext: viewContext, objectID: item.objectID)
        }
        
        func didDismiss() {
            // Handle the dismissing action.
        }
    }
    
    struct ContentView: View {
        @Environment(\.managedObjectContext) private var viewContext
    
        @FetchRequest(
            sortDescriptors: [NSSortDescriptor(keyPath: \Item.timestamp, ascending: true)],
            animation: .default)
        private var items: FetchedResults<Item>
        
        var body: some View {
            NavigationView {
                
                List {
                    ForEach(items) { item in
                        NavigationLink {
                            DetailView(item: item)
                        } label: {
                            Text(item.timestamp!, formatter: itemFormatter)
                        }
                    }
                    .onDelete(perform: deleteItems)
                }
                .toolbar {
                    
                    ToolbarItem(placement: .navigationBarTrailing) {
                        EditButton()
                    }
                    ToolbarItem {
                        Button(action: addItem) {
                            Label("Add Item", systemImage: "plus")
                        }
                    }
                }
                Text("Select an item")
            }
        }
    
        
        private func addItem() {
            withAnimation {
                let newItem = Item(context: viewContext)
                newItem.timestamp = Date()
    
                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)")
                }
            }
        }
    
        private func deleteItems(offsets: IndexSet) {
            withAnimation {
                offsets.map { items[$0] }.forEach(viewContext.delete)
    
                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)")
                }
            }
        }
    }
    
    private let itemFormatter: DateFormatter = {
        let formatter = DateFormatter()
        formatter.dateStyle = .short
        formatter.timeStyle = .medium
        return formatter
    }()
    
    struct ContentView_Previews: PreviewProvider {
        static var previews: some View {
            ContentView().environment(\.managedObjectContext, PersistenceController.preview.container.viewContext)
        }
    }
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

swiftui 如何从详细信息到编辑视图获取核心数据值 的相关文章

  • 如何从 iPhone 中删除 coredata

    您知道当您更改实体结构时如何重置 iPhone 模拟器上的核心数据存储吗 当我创建的核心数据存储的新版本与我上次在 iPhone 上运行的版本不同时 是否需要执行类似的过程 如果可以的话 请问如何 Thanks 只是为了方便起见 除非您编写
  • NSOperationQueue 和 NSFetchedResultsController

    我使用队列和结果控制器的组合来更新和显示一些核心数据对象 在我的 uitableviewcontroller 中 我每隔 X 秒调用一次主控制器对象中的方法 NSTimer scheduledTimerWithTimeInterval 2
  • 如何防止“CoreData无法完成故障”?

    我们偶尔会收到 CoreData 无法完成故障 的信息 我们已阅读 Apple 文档 但不清楚允许保留哪些内容 我们非常小心地为每个线程创建一个上下文等 但是 我们的应用程序正在做的一件事是我们在 UIViewController 上保留
  • iOS 8 核心数据堆栈 - 致命错误:在解包可选值时发现 nil

    我对 iOS 开发比较陌生 决定实现自己的 Core Data 堆栈 替换 Apple 的默认堆栈 我必须对我的代码进行更改 显然 并且能够弄清楚它 但在这种情况下我不能 这是我的代码 import UIKit import CoreDat
  • 强制设置核心数据检查点?

    我编写了一个通过 Core Data 搅动大量数据的应用程序 用户在后台退出应用程序后 我会清理这些数据 由于 WAL 检查点似乎是导致 UI 暂停的主要原因 因此我还想强制使用 WAL 检查点 是的 我知道创建第二个核心数据堆栈 这也将完
  • Swift NSSet 和 CoreData

    我正在尝试将目标 C 和 CoreData 应用程序移动到 Swift 和 iOS 但在迭代 NSSet 对象时遇到了困难 Xcode 已生成这些类 class Response NSManagedObject NSManaged var
  • 使用 CoreData 进行 Swift 包单元测试

    我有一堆快速文件 它们提供了 CoreData 之上的一些服务 我的单元测试运行良好 我决定使用 XCode 11 将所有这些移至 Swift 包中 单元测试不再运行 运行时错误为caught NSInternalInconsistency
  • 使用简洁形式的 NSManagedObjectID URI?

    在我的应用程序中 我使用 Core Data 以及不使用 Core Data 的附加 sqlite 数据库 在这个附加数据库中 我有一些列存储对NSManagedObject实例通过每个实例的NSManagedObjectID 我得到一个实
  • 如何按月对获取的日期进行分组

    我将数据插入到日期类型的核心数据中 但是当我尝试从数据库中获取数据时 我无法按月对它们进行分组 您可以找到我尝试解决方案的代码 但它不起作用 let groupedDict Dictionary grouping self lessons
  • NSFetchRequest 不返回任何内容

    任何人都可以发现为什么这不返回任何 ManagedObjects 吗 我试图将以下内容添加到 ATNSManagedObject EasyFetching 类中 但获取结果不返回任何内容 如果我在 EasyFetch 类之外获取这些对象 我
  • 如何使用 Core Data (iPhone) 存储 CLLocation?

    我试图保存一个位置 然后使用 Core Location MapKit 和 Core Data 框架在地图上检索该位置 我所做的只是创建了名为 POI 的实体 并添加了诸如纬度 双精度类型 经度 双精度类型 等属性以及其他一些属性 简而言之
  • 跳过痛苦的 Core Data 迁移并迁移到新的数据模型

    当我什至不关心旧数据时 我花费了大量时间将核心数据整理到新的迁移中 有没有一种方法可以删除所有现有数据并跳转到新的数据模型 而不是每次更改数据模型时都处理映射模型的麻烦 是的 只需删除商店文件并重新创建即可 我经常 至少在开发过程中 让我的
  • 如何让NSManagedObject不出错?

    我目前正在调试另一个开发人员编写的一个大项目 该项目使用CoreData我对此很陌生 我遇到了崩溃 这是由于某些NSManagedObject是一个错误 我对什么是错误不太了解 我想将对象转换为 非错误 看看它是否有帮助 阅读文档让我想到t
  • 如何为现有核心数据实体添加更多属性?

    我有一个正在使用核心数据的项目 我需要向现有实体 列 添加更多属性 列 如果我手动将属性添加到数据模型应用程序崩溃 这是由于我用来将数据插入表的上下文保存之前 请帮助 谢谢 所以我的问题是我不知道这个持久存储协调器代码去了哪里 事实证明它是
  • 更改 NSManagedObject 属性而不触发委托方法?

    有什么方法 或技巧 可以修改NSManagedObject目前由一名代表持有NSFetchedResultsController不触发didChangeObject and controllerWillChangeContent 委托方法
  • Swift 2.0 中的 countForFetchRequest

    我正在尝试使用countForFetchRequestSwift 2 0 中托管对象上下文上的方法 我注意到错误处理executeFetchRequest已更改为新的do try catch syntax func executeFetch
  • Xcode 4 Core Data:如何使用在数据模型编辑器中创建的获取属性

    如何在 Xcode 4 中实现获取的属性 Here is an example of two entities a book and a page 我按照此处的指南创建了一个获取的属性 该属性使用变量 FETCH SOURCE 引用来自源实
  • 使用按计数分组的核心数据获取属性

    这是我想为 Core Data 编写的查询的 SQL 版本 SELECT Group Name COUNT Item Name FROM Item INNER JOIN Group ON Item GroupID Group ID GROU
  • 如何在 SwiftUI 中使用带条件检查的按钮进行导航

    Since 导航按钮不再可用 我如何检查条件导航链接为了导航到另一个视图 NavigationLink destination Dashboard userName self userId password self password is
  • 核心数据对多关系。它们是延迟加载吗?

    我在核心数据 适用于 iPhone 中有典型的模型 其中包含部门和员工 部门 gt gt 员工 我不想每次加载时都加载一个部门的所有员工 所以我想将员工创建为获取的属性 我想我可以定义一些像这样的谓词 employee deparmentI

随机推荐

  • 在Linux上编译VLC:错误找不到Lua

    我正在尝试为 Linux 编译 VLC 当我运行配置脚本时 我收到错误消息 配置 错误 找不到 lua 有些人需要Lua 接口 rc telnet http 以及许多其他自定义脚本 使用 disable lua 忽略此错误 我的系统上有lu
  • Ruby,没有将 Symbol 隐式转换为 Integer

    昨天我已经在 没有将 Symbol 隐式转换为 Integer Ruby https stackoverflow com questions 38482973 no implicit conversion of symbol into in
  • shell命令SET -X在脚本中的意思[重复]

    这个问题在这里已经有答案了 所以我有一个文件部署 sh 并且它有 shell 脚本 自从我知道这件事以来 我就有点困惑 这是什么意思set x实际上意味着 运行该文件后 我观察到在文件中的命令后面写入的命令在终端中被提及 sign 就像如果
  • 文档中的 tf.data.Dataset.window 示例失败

    我正在尝试使用一个例子TF文档 https www tensorflow org api docs python tf data Dataset window for tf data Dataset window并且文档中的示例失败了 源自
  • 使用外键批量插入表

    我有一个客户表 其中包含客户的详细信息 以下是字段 CustId PrimaryKey Name Date of Birth 我有另一个表 资产信息 有以下字段 AssetId PrimaryKey AssetValue CustId Fo
  • 尝试执行 jQuery AJAX 调用时 JavaScript 错误意外标识符

    我有这个 jQuery 代码
  • 当前上下文中不存在名称“SqlDataSourceEnumerator”

    在 Visual Studio 中的 C net 5 程序中 我正在测试使用 SqlDataSourceEnumerator 的代码 public static List
  • 全关联缓存是否比直接映射缓存具有更高的未命中率?

    以下是一个面试问题 为什么全关联缓存的未命中率可能高于直接映射缓存 我认为这根本不可能 有人可以分享一些对此的见解吗 你应该假设它们大小相同吗 如果不是 则如果大多数未命中是 容量 未命中 而不是冲突未命中 则较小的全关联高速缓存仍然可能会
  • 如何让MySQL正确处理UTF-8

    的回应之一我昨天问的一个问题 https stackoverflow com questions 198721 converting a word document into usable html in php建议我确保我的数据库可以正确
  • 更新反应组件而没有父组件在其之外

    如果组件没有父组件 我应该如何正确更新组件 我找到了两种方法来做到这一点 第一种方法 https jsfiddle net 69z2wepo 28597 这里我通过改变组件的状态来更新组件 var Hello React createCla
  • 捕获无法处理的异常并重新加注

    这是我的问题的后续使用 SQLAlchemy 和多处理挂入 Python 脚本 https stackoverflow com questions 8785899 hang in python script using sqlalchemy
  • jquery 附加到列表的前面/顶部

    我有这个无序列表 ul li two li li three li ul 有没有办法可以将其添加到无序列表中 使其最终像这样 ul li ONE li li two li li three li ul 请注意 ONE 已添加到列表的前面 顶
  • 打开 ViewPager2 到特定位置而不滚动

    我已经用一些视频实现了回收视图 say 10 单击任何项 目都会打开一个viewpager2 which is on some other activity与所有物品and单击的一个 来自recyclerview 显示 之后 用户只能从那里
  • 是否可以让 Visual Studio 索引源代码以改进字符串搜索?

    我经常在 VS2008 中使用字符串搜索功能来构建整个解决方案 有没有办法通过让 VS2008 索引所有源代码和配置文件来提高其搜索速度 类似于 Google 桌面索引文件的方式 这增加了对 VS 解决方案中所有文件的即时全文搜索 不是免费
  • 设置 Gin 中未找到的路由

    我在 Gin 中设置了默认路由器和一些路由 router gin Default router POST users save router GET users getAll 但是我该如何处理 Gin 中找不到 404 路线呢 最初 我使用
  • 如何处理 JSF 中的动态角色或用户名更改?

    我有一个在 glassfish 2 1 上运行的 JSF 应用程序 具有 EJB 3 后端 对于身份验证 我使用自定义领域 用户使用他在注册时指定的电子邮件地址和密码进行身份验证 一切都运转良好 现在我有两个相关的问题 1 用户可以编辑他的
  • Xcode 4 Preview 2 是否足够稳定,可以用于开发?

    Xcode 4 Preview 2 是否足够稳定 可以用于开发 由于最终版本已经出来 这个线程可以忽略 从我最近看到的情况来看 它相当不稳定 在崩溃之前很难使用它超过几分钟 我当然不会在实际项目中使用它
  • 任务中重新抛出异常 (TPL) 丢失堆栈跟踪

    我有重新抛出异常的代码 当我后来从 task Exception 读取异常时 它的堆栈跟踪指向我重新抛出异常的位置 如我所料 第 n 行而不是第 m 行 为什么会这样呢 TPL 中的错误或更可能是我忽略的东西 当我解决方法时 我可以将异常包
  • Visual Studio Code - 按文件夹对待处理的更改进行分组

    由于某些受支持的扩展 我想摆脱当前的 IDE Jetbrains 并迁移到 Visual Studio Code VS Code 中我只缺少一件事 如果我在源代码管理中有多个文件作为待处理的更改 它们只会显示为平面列表 例如IntelliJ
  • swiftui 如何从详细信息到编辑视图获取核心数据值

    通过使用核心数据构建应用程序来学习 swiftui 陷入AddEdit的Detail到Edit的数据流向问题 从 AddEdit 到 List 以及从 List 到 Detail 的流程都可以 在网上搜索但没有找到有用的信息或者我不明白 这