SwiftUI 尝试读取小部件内的 CoreData 总是返回空?

问题描述 投票:0回答:1

我正在尝试从我的应用程序小部件扩展读取我的应用程序 CoreData 文件。

读取成功,但当我的应用程序成功读取数据时,数据获取始终返回空。

这里是祈祷实体:(目标成员资格选择为小部件和应用程序)

这是我的小部件类:

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 和苹果社区中有关他的问题的每个主题,并且尝试了几乎所有尝试从应用程序小部件读取 CoreData 的解决方案,所有尝试都失败了,上下文中的结果为空。当我 100% 确定数据库已充满记录时。

swift core-data widget
1个回答
0
投票

仅设置目标会员资格是不够的。这只会将实体暴露给 Widget 代码。它不与 Widget 扩展共享底层数据库。 0

您需要为应用程序和扩展程序设置一个相同的应用程序组。然后为应用程序组创建数据库 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
}

但请注意:该数据库将为空。如果您以前的数据库中已有数据,则必须迁移。

© www.soinside.com 2019 - 2024. All rights reserved.