Search code examples
iosswiftcore-dataswiftuiwidgetkit

How to get random Core Data element from ForEach in Widget


I'm working on a widget in iOS 14 that will show images from Core Data as submitted by my users. Currently, I can show a single image, but it's not rotating through the Project images.. it's only showing a single image in the widget.

In my Widget.swift, the only way I can get an image to show is by using a ForEach. If I don't use the ForEach, I get the error Value of type 'FetchedResults<Project>' has no member 'image1'

Here's the (mostly) working code

struct WidgetEntryView : View {
    var entry: Provider.Entry
    @State var projectImage1: Data = .init(count: 0)
    @FetchRequest(entity: Project.entity(), sortDescriptors: []) var project: FetchedResults<Project>
    
    var body: some View {
    
            ForEach((project.prefix(1)), id: \.self) { (project: Project) in
                Image(uiImage: UIImage(data: project.image1 ?? self.projectImage1) ?? UIImage(imageLiteralResourceName: "icon"))
                    .resizable()
                    .aspectRatio(contentMode: .fill)
            }.environment(\.managedObjectContext, managedObjectContext)
    }
}

Again, if I use the below code, I get the no member error for some reason

struct WidgetEntryView : View {
    var entry: Provider.Entry
    @State var projectImage1: Data = .init(count: 0)
    @FetchRequest(entity: Project.entity(), sortDescriptors: []) var project: FetchedResults<Project>
    
    var body: some View {
        
       Image(uiImage: UIImage(data: project.image1 ?? self.projectImage1) ?? UIImage(imageLiteralResourceName: "icon"))
                    .resizable()
                    .aspectRatio(contentMode: .fill)
        }.environment(\.managedObjectContext, managedObjectContext)
    }
}

How can I have the ForEeach show a random project.image1 attribute? I've tried appending randomElement() and shuffle() but neither are accepted.

Here's the full Widget.swift: https://pastebin.com/aFMuZ0iz


Solution

  • FetchedResults<Project> is a collection data type, so it won't have an image1 property like an element in the collection of type Project. You're using the prefix(1) method which is returning a sub-collection with one element...but it's still a collection.

    Try something like this:

    if let randomProject: Project = project.randomElement()
    {
       Image(uiImage: UIImage(data: randomProject.image1 ?? self.projectImage1))
    }
    else
    {
       Image(uiImage: UIImage(imageLiteralResourceName: "icon"))
    }
    

    project.randomElement() will return a random element from the collection if not empty, else nil.