UPGRADE YOUR SKILLS: Learn advanced Swift and SwiftUI on Hacking with Swift+! >>

Day55 – Making Previews work for DetailView

Forums > 100 Days of SwiftUI

The following code doesn't work. The diagnostics says something like: "An NSManagedObject of class 'Book' must have a valid NSEntityDescription."

struct DetailView_Previews: PreviewProvider {
    static let moc = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)

    static var previews: some View {
        let book = Book(context: moc)
        book.title = "Test book"
        book.author = "Test author"
        book.genre = "Fantasy"
        book.rating = 4
        book.review = "This was a great book; I really enjoyed it."

        return NavigationView {
            DetailView(book: book)
        }
    }
}

Does somebody have a solution?

2      

@npy  

Hello ! I have the same problem, does anyone have a solution ?

2      

Same here... I am using Xcode 13.4, built for iOS 15.5, tried simulating on iPod touch (7th generation), iPhone 12, iPad (9th generation).

2      

I was able to fix the issue by adding a Persistence.swift file following the example code here: https://www.hackingwithswift.com/forums/100-days-of-swiftui/day-54-bookworm-an-nsmanagedobject-of-class-book-must-have-a-valid-nsentitydescription/5043

I really like the solution from the video however which is just to delete all the preview code from DetailView.swift.

2      

The general question here is:

How do I show mock core data objects in a SwiftUI preview provider?

I have another suggestion.

Check out Mark Moeykens' excellent eBook titled, Core Data Quick Start in SwiftUI dated, 22 June 2022.

Our own @twoStraws is mentioned in the opening credits.

Mark writes nearly nine pages with plenty of notes and graphics explaining how to populate a temporary CoreData datastore with sample objects so that you can view fake CoreData records in your previews. Sweet!

The book is excellent and is free.

See -> Mark's Excellent Core Data Book

3      

Thanks @Obelix, was looking how to do this, and downloaded that book and now I can happily design my screen in the preview with fake core data :)

So you don't have to go digging in the book you can create a PreviewDataController under the Preview Content folder of your project...

class PreviewDataController {

    private let container = NSPersistentContainer(name: "DiceRolls")

    var viewContext: NSManagedObjectContext {
        container.viewContext
    }

    init() {
        container.persistentStoreDescriptions.first!.url = URL(fileURLWithPath: "/dev/null")

        container.loadPersistentStores { description, error in
            if let error = error {
                print("Core Data failed to load: \(error.localizedDescription)")
            }
        }
    }

    func savePreviewData(diceRolls: [[String : Any]]) {

        diceRolls.forEach { diceRollDict in
            let diceRoll = DiceRoll(context: container.viewContext)
            diceRoll.id = UUID()
            diceRoll.totalRolled = diceRollDict["totalRolled"] as! Int16
            diceRoll.numberOfSides = diceRollDict["numberOfSides"] as! Int16
            diceRoll.numberOfDice = diceRollDict["numberOfDice"]  as! Int16
            diceRoll.dateOfRoll = diceRollDict["dateOfRoll"] as? Date
        }
    }
}

Then in your preview...

struct PreviousRollsView_Previews: PreviewProvider {

    private static let diceRolls = [
        [
            "totalRolled": Int16(4),
            "numberOfSides": Int16(6),
            "numberOfDice": Int16(1),
            "dateOfRoll": Date()
        ],
        [
            "totalRolled": Int16(12),
            "numberOfSides": Int16(6),
            "numberOfDice": Int16(2),
            "dateOfRoll": Date()
        ],
        [
            "totalRolled": Int16(14),
            "numberOfSides": Int16(4),
            "numberOfDice": Int16(4),
            "dateOfRoll": Date()
        ],
    ]

    static var previews: some View {
        let previewDataController = PreviewDataController()

        previewDataController.savePreviewData(diceRolls: diceRolls)

        return PreviousRollsView(isPresented: .constant(true))
            .environment(
                \.managedObjectContext,
                 previewDataController.viewContext
            )
    }
}

2      

Hacking with Swift is sponsored by RevenueCat.

SPONSORED Take the pain out of configuring and testing your paywalls. RevenueCat's Paywalls allow you to remotely configure your entire paywall view without any code changes or app updates.

Learn more here

Sponsor Hacking with Swift and reach the world's largest Swift community!

Archived topic

This topic has been closed due to inactivity, so you can't reply. Please create a new topic if you need to.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.