我正在try 从我的app Widget扩展读取我的app CoreData文件.

读取成功,但当我的应用程序成功读取数据时,数据获取总是返回空.

here is Prayers Entity : ( Target membership is selected to widget and app ) enter image description here

这是我的小部件类:

import WidgetKit
import SwiftUI
import CoreData

class CoreDataStack {
    static let shared = CoreDataStack()

    lazy var persistentContainer: NSPersistentContainer = {
        let container = NSPersistentContainer(name: "Prayers")
        let storeURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.xxx.test.xxx.test")!.appendingPathComponent("Prayers.sqlite")
        let description = NSPersistentStoreDescription(url: storeURL)
            description.shouldMigrateStoreAutomatically = true
            description.shouldInferMappingModelAutomatically = true
        
        container.persistentStoreDescriptions = [description]
        container.loadPersistentStores(completionHandler: { (storeDescription, error) in
            if let error = error {
                fatalError("Unresolved error \(error)")
            }
        })
        return container
    }()
}

struct widgetsEntryView : View {
    
    var entry: Provider.Entry
    @State private var lineY:CGFloat = 0
    @State var zz:CDPrayer!
    @State var zzzzzzzz:String =  ":))"
    
    var body: some View {
        
        ZStack{
            
            GeometryReader { proxy in
                
                HStack(alignment: .center, spacing: 0){
                    
                    if zz != nil {
                        prayerBiteVertical(prayer:zz,proxy:proxy,lineY : $lineY)
                    }else{
                        Text(zzzzzzzz)
                            .font(.system(size: 9))
                    }
                }
                
            } .coordinateSpace(name: "_geo")
                .onChange(of: entry.date) { oldValue, newValue in
                loadDate()
            }.onAppear(){
                loadDate()
            }
            
        }
        
    }
    
    func loadDate(){
        
        let managedObjectContext = CoreDataStack.shared.persistentContainer.viewContext

        let fetchRequest  = CDPrayer.fetchRequest()
        
        do{
            let prayers =  try managedObjectContext.fetch(fetchRequest) 
        
            zzzzzzzz = "ok \(prayers)"
            
            //They r 5 prayers we r good
            if prayers.count == 5 {
                zz = prayers.filter{$0.prayer == "Fajr"}[0]
            }
        
        } catch let error as NSError {
            zzzzzzzz = "[PrayerTimes][WIDGET] Could not fetch. \(error), \(error.userInfo)"
        }
       
    }
   
}


struct prayerBiteVertical : View  {
    
    @State var prayer:CDPrayer
    @State var proxy:GeometryProxy!
    @Binding var lineY:CGFloat
    @State var btn:btton_themes = .normal
    
    //Keys
    @State var key_prayer:String = ""
    
    var body: some View {
       
        ZStack{
            
            Color("highlightBg")
            
            GeometryReader{ g in
        
                Color.clear.onAppear(){
                    lineY = g.frame(in: .named("_geo")).minY
                }
                
            }.frame(height :0.1)
            
            VStack{
                
                Text(key_prayer)
                    .font(.poppins(.Regular,size: 15))
                    .minimumScaleFactor(0.85)
                
                Image(systemName: "sunset.fill")
                    .resizable()
                    .aspectRatio(contentMode: .fit)
                    .frame(width : 25)
                    .frame(height : 20)
               
                Text("11:11")
                    .font(.poppins(.Regular,size: 18))
                    .minimumScaleFactor(0.85)
                
                Spacer()
            }
            
          
        }.frame(width : proxy.frame(in: .local).width * 0.2)
        .onChange(of: prayer) { oldValue, newValue in
            
            key_prayer = prayer.prayer!
            
        }
        
    }
    
}


struct widget_Medium: Widget {
    
    let kind: String = "widgets"
    var body: some WidgetConfiguration {
        
        AppIntentConfiguration(kind: kind, provider: Provider()) 
        { entry in
            
            widgetsEntryView(entry: entry)
                .containerBackground( .clear, for: .widget)
         
        }.supportedFamilies([.systemMedium])
         .containerBackgroundRemovable(true)
         .configurationDisplayName("My Widget")
         .description("This is an example widget.")
         
        
    }
}

struct SimpleEntry: TimelineEntry {
    let date: Date
    let configuration: ConfigurationAppIntent
}


struct Provider: AppIntentTimelineProvider {
    
    func placeholder(in context: Context) -> SimpleEntry {
        SimpleEntry(date: Date(), configuration: ConfigurationAppIntent())
    }

    func snapshot(for configuration: ConfigurationAppIntent, in context: Context) async -> SimpleEntry {
        SimpleEntry(date: Date(), configuration: configuration)
    }
 
    func timeline(for configuration: ConfigurationAppIntent, in context: Context) async -> Timeline<SimpleEntry>
    {
        var entries: [SimpleEntry] = []

        // Generate a timeline consisting of five entries an hour apart, starting from the current date.
        let currentDate = Date()
        for hourOffset in 0 ..< 60 
        {
            let entryDate = Calendar.current.date(byAdding: .minute, value: hourOffset, to: currentDate)!
            let entry = SimpleEntry(date: entryDate, configuration: configuration)
                entries.append(entry)
        }

        return Timeline(entries: entries, policy: .atEnd)
    }
}

#Preview(as: .systemMedium) {
    widget_Medium()
} timeline: {
    SimpleEntry(date: .now, configuration: ConfigurationAppIntent())
}

PS:我几乎关注了SOF和苹果社区中关于他问题的每一个话题,我try 了几乎所有试图从应用程序窗口小部件读取CoreData的解决方案,所有try 都失败了,上下文中的结果都是空的.当我100%确定数据库中有记录时.

推荐答案

仅设置目标成员身份是不够的.这只会将实体expose 给Widget代码.它不与Widget扩展共享底层数据库.

您需要将应用程序组设置为相同的for both、应用程序和扩展.然后为应用程序组创建数据库URL,并在小部件和应用程序中使用该数据库.

例如:

init(inMemory: Bool = false) {
    container = NSPersistentContainer(name: "TestCoreData")
    let url = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "app.group.identifier")?.appendingPathComponent("databasename.sqlite")
    let storeDescription = NSPersistentStoreDescription(url: url!)
    container.persistentStoreDescriptions = [storeDescription]
    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)")
        }
    })
    container.viewContext.automaticallyMergesChangesFromParent = true
}

但请注意:此数据库将为空.如果您以前的数据库中已有数据,则必须进行migrations.

Swift相关问答推荐

通过withstickedContinuation传递通用类型T

如何在Swift 中创建移动的uil标签?

如何更新Square Order?

如何在realityKit中反转USDZ动画

字符串目录不适用于SWIFT包

如何在visionOS上删除PhotosPicker背景 colored颜色 ?

出错-无法将季节类型的值转换为预期的参数类型';[水果]';

如何使泡泡上的箭头直达封闭矩形

如何将多个完成处理程序转换为异步?

如何为我的项目设置生命周期选项?

Xcode 15 Beta中如何使用@Observable?

从文字创建数组时的 Swift 宏

将每个枚举 case 与 Swift 中的一个类型相关联

在 Vapor 4 中使用协议的通用流利查询

如何在 SwiftUI 中将图像传递到 2 个视图

如何 for each 用户制作一个单独的按钮,以便在按下它时切换 isFollowingUser Bool 并更改为关注?

Swift Swiftui - 将 colored颜色 保存到 UserDefaults 并从 @AppStorage 使用它

将阻塞函数集成到 Swift 异步中

如何更改弹出框的大小

swift 中的@property/@synthesize 类似功能