2

I have been trying to get my detail view working but when giving the preview arguments of the currently selected item from the list it keeps giving me an error Cannot convert value of type 'Item.Type' to expected argument type 'Item'

Here is the detailview

import SwiftUI
import CoreData

struct FishDetailView: View {

    var item: Item

    @State var image : Data = .init(count: 0)
    
    var body: some View {
        Text(item.title ?? "")
        Text(item.details ?? "")
        Image(uiImage: UIImage(data: item.imageData ?? self.image)!)
            .resizable()
            .frame(width: UIScreen.main.bounds.width - 34, height: 210)
            .cornerRadius(15)
    }
}

struct FishDetailView_Previews: PreviewProvider {
    static var previews: some View {
        
        FishDetailView(item: Item) **<--- THE ERROR HAPPENS HERE**
    }
}

Contentview.swift

import SwiftUI
import CoreData

struct ContentView: View {
    // MARK: - PROPERTY

    @State var title: String = ""
    @State private var showSheet: Bool = false
    @State var image : Data = .init(count: 0)
    @Environment(\.managedObjectContext) var viewContext

        @FetchRequest(
        sortDescriptors: [NSSortDescriptor(keyPath: \Item.timestamp, ascending: true)],
        animation: .default)
    private var items: FetchedResults<Item>
    
    // MARK: - FUNCTION
    private func deleteItems(offsets: IndexSet) {
        withAnimation {
            offsets.map { items[$0] }.forEach(viewContext.delete)

            do {
                try viewContext.save()
            } catch {
                let nsError = error as NSError
                fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
            }
        }
    }
    
    //: MARK - BODY

    var body: some View {
        NavigationView {
            VStack {
              
                List {
                    ForEach(items, id: \.self) { item in
                        NavigationLink(destination: FishDetailView(item: item)) {
                            Image(uiImage: (UIImage(data: item.imageData ?? self.image) ?? UIImage(systemName: "photo"))!)
                                .resizable()
                                .frame(width: UIScreen.main.bounds.width - 34, height: 210)
                                .cornerRadius(15)
                            HStack {
                                Text("\(item.details ?? "")")
                                
                            }//:HSTACK
                        }
                        // TODO: Insert timestamp here with .footnote font
                        }
                    }
                    
                    if showSheet {
                        AddFishView()
                    }
                }//: LIST
                .navigationBarTitle("Fishes", displayMode: .large)
                .navigationBarItems(trailing: Button(action: {
                    self.showSheet.toggle()
                })
                   {
                    Image(systemName: "camera.fill")
                })
                .sheet(isPresented: self.$showSheet) {
                    AddFishView()
                }
            } //: VSTACK
        } //: NAVIGATION
    }

// MARK: - PREVIEW

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        let persistenceController = PersistenceController.shared
        ContentView().environment(\.managedObjectContext, persistenceController.container.viewContext)
    }
}

The detailview does work if I remove the preview section of the code but it's not really ideal since I would like to see what I'm doing without having to open the app in simulator every time I do a change.

I can't seem to work out why it does it or how to fix it. Someone with better brains can help out?

The code is little bit messy because this is just a test I'm doing where I'm saving a users image into Core Data.

EDIT: already tried this that was suggested but didn't seem to fix my issue PreviewProvider and ObservedObject properties

Here is the Item entity Entity image

2
  • Does this answer your question? PreviewProvider and ObservedObject properties Commented Aug 2, 2022 at 14:10
  • In this case I would recommend protocol instead of direct dependency on Core Data Item and mock for Preview Commented Aug 2, 2022 at 14:29

2 Answers 2

5
import SwiftUI
import CoreData

struct FishDetailView: View {

    @ObservedObject var item: Item

    var body: some View {
        Text(item.title ?? "")
        ...
        // fyi your image should be a transformable attribute on the Item entity
    }
}

struct PreviewTestView_Previews: PreviewProvider {
    
    static var firstItem: Item? {
        let context = PersistenceController.preview.container.viewContext
        let fetchRequest = Item.fetchRequest()
        fetchRequest.fetchLimit = 1
        let results = try? context.fetch(fetchRequest)
        return results?.first
    }
    
    static var previews: some View {
        if let firstItem {
            FishDetailView(item: firstItem)
        }
        else {
            Text("Item not found")
        }
    }
}
Sign up to request clarification or add additional context in comments.

4 Comments

While this may work now, take note that uses a couple of force-unwraps which may cause your previews to explode and stop working later. It is now also dependent on there being data in your Core Data database just for the preview to load. Sure, they're only SwiftUI previews, but I'd still recommend using a plain Swift object (see this search.
@acodeguy thank you i will be taking a look at that.
@acodeguy ok ok I removed the force-unwraps. We need a real NSManagedObject so validation works etc. in live preview.
It's definitely better without the force-unwraps, but the dependency on persistence would bother me if this were in a PR to go into a production app; if this is just a demo for learning, then that could always be taken into consideration on a future iteration/project
0

It looks like you're trying to feed the preview a type rather than an instance of a type:

FishDetailView(item: Item)

Perhaps this is what you're trying to do instead:

let item = Item(/* init here */)
return FishDetailView(item: item)

or

FishDetailView(item: Item(/* init here */))

11 Comments

What is even supposed to place in the init here place?
@John I couldn't see the Item class or struct so I just left how to initialize it a blank. If you post it's code I'd be happy to help further with creating one
Init is it supposed to be like title: "the title"
I added the Item entity picture. Hopefully it helps. I have selected the codegen to Class selection instead of manual/none. Do I need to make my own struct of the Item. Sorry this core data is new to me since I just started learning it.
Previews can get a little difficult to manage when you involve Core Data entities; I always go down the route of using plain Swift object to represent them, so instead of an Item, I'd have an ItemViewModel or something that holds similar data needed to represent the Core Data model.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.