SwiftUI 如何使 CoreData 列表在 macOS 上可选择和可双击

Posted

技术标签:

【中文标题】SwiftUI 如何使 CoreData 列表在 macOS 上可选择和可双击【英文标题】:SwiftUI How to make CoreData list selectable and double clickable on macOS 【发布时间】:2020-12-09 18:11:54 【问题描述】:

我有一个可选择和双击的名称列表。 我有一个 CoreData 记录列表,我无法选择或双击。

如何使 CoreData 列表可选择和双击?

这是我正在使用的可选列表代码:

import SwiftUI

struct ContentView: View 
    private static let values = ["Luke","Han","Chewie","Liea","R2D2"]
    
    @State private var selection: String? = nil
    
    var body: some View 
        VStack 
            HStack 
                List(Self.values, id: \.self, selection: $selection)  name in
                    Text(name)
                        .gesture(TapGesture(count: 2).onEnded 
                            print("double clicked")
                            selection = name
                        )
                        .simultaneousGesture(TapGesture().onEnded 
                            print("single clicked")
                            selection = name
                        )
                
            
        
    

这是我的 ManagedObject:

@objc(Enquiry)
public class Enquiry: NSManagedObject 


这是显示列表的 CoreData 列表:

import SwiftUI
import CoreData

struct EnquiryList: View

    @Environment(\.managedObjectContext) private var viewContext
    
    var enquiries: FetchRequest<Enquiry>
    
    init (uuid: UUID)
    
        enquiries = FetchRequest<Enquiry>(entity: Enquiry.entity(), sortDescriptors: [], predicate: NSPredicate(format: "UUID == %@", uuid as CVarArg))
    
    @State private var selection: Enquiry? = nil
    
    var body: some View
    
        VStack
        
            ForEach(enquiries, id: \.self, selection: $selection)
            enquiry in
                EnquiryListRow(enquiry: enquiry)
                    .gesture(TapGesture(count: 2).onEnded 
                        print("double clicked")
                        selection = enquiry
                    )
            
        
    

ForEach 行给出以下错误:

我错过了什么?最终我想选择记录,然后双击打开一个带有查询的窗口。

根据 Asperi 的回答更改代码并没有让我更进一步:

List(enquiries.wrappedValue, id: \.self, selection: $selection)
enquiry in
    Text("Hello")

enquiries.wrappedValue.count 显示有 3 条记录,但没有任何显示。将其移回 ForEach 将显示 Hello 三次。

【问题讨论】:

第二个例子不起作用?第一个对我来说很好 是的,这是我的问题。如何使第二个示例像第一个示例一样工作。 【参考方案1】:

如果没有您丢失的代码,重现错误有点困难。不过,我已经编写了一些代码,您可以复制和粘贴这些代码以使工作正常进行。

请在下面找到我经过测试和工作的示例:

import SwiftUI
import Foundation
import CoreData

class PersistentContainer 
    public static var container: NSPersistentContainer = 
        let container = NSPersistentContainer(name: "DataModel")
        container.loadPersistentStores(completionHandler:  (storeDescription, error) in
            if let error = error as NSError? 
                    fatalError("Unresolved error \(error), \(error.userInfo)")
            
        )
        container.viewContext.automaticallyMergesChangesFromParent = true
        container.viewContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
        
        return container
    ()
    
    private init() 


class DataModel: ObservableObject 
    private var _context: NSManagedObjectContext
    @Published public var Enquiries: [Enquiry]
    
    init() 
        self._context = PersistentContainer.container.viewContext
        self.Enquiries = try! self._context.fetch(Enquiry.fetchRequest())
    


struct EnquiryListRow: View 
    public var Enquiry: Enquiry
    
    var body: some View 
        Text("\(self.Enquiry.name ?? "(no name given)")")
    


struct ContentView: View 
    @StateObject var model = DataModel()
    @State private var selection: Enquiry? = nil
    
    var body: some View 
        List(self.model.Enquiries, id: \.self, selection: self.$selection)  enquiry in
            EnquiryListRow(Enquiry: enquiry)
                .gesture(TapGesture(count: 2).onEnded 
                    print("double clicked")
                    self.selection = enquiry
                )
                .simultaneousGesture(TapGesture().onEnded 
                    print("single clicked")
                    self.selection = enquiry
                )
        
    


struct ContentView_Previews: PreviewProvider 
    static var previews: some View 
        ContentView()
    

【讨论】:

【参考方案2】:

您也应该在第二种情况下使用 List - ForEach 只是一个没有 selection 功能的动态组:

var body: some View

    VStack
    
        List(selection: $selection)     // << here !!
        ForEach(enquiries, id: \.self)
        enquiry in
            EnquiryListRow(enquiry: enquiry)
                .gesture(TapGesture(count: 2).onEnded 
                    print("double clicked")
                    selection = enquiry
                )
        
    

【讨论】:

如果我做出改变,我会得到 Initializer 'init(_:id:selection:rowContent:)' 要求 'FetchRequest' 符合 'RandomAccessCollection'。有什么建议吗? 这不起作用。我不得不在 List 中使用 WrappedValue 来编译它,但是它没有显示任何行。恢复到 ForEach(没有选择)确实显示了行。 我没有你的所有代码,所以无法测试,请尝试更新 - 结合 List 和 ForEach,如果后者适合你。 在 ForEach 周围添加列表会导致不再显示行。

以上是关于SwiftUI 如何使 CoreData 列表在 macOS 上可选择和可双击的主要内容,如果未能解决你的问题,请参考以下文章

SwiftUI 使用 CoreData 从列表中编辑项目

SwiftUI - 如何在 CoreData 中删除实体中的行

SwiftUI 2.0列表项层级缩进显示CoreData托管数据的3种实现

SwiftUI 2.0列表项层级缩进显示CoreData托管数据的3种实现

如何在 SwiftUI 中使用 CoreData 更改数据值?

SwiftUI:如何将 CoreData 与动态过滤器相加?