Xcode & SwiftUI - How to reset Canvas?
Asked Answered
A

1

10

Question: How to reset Xcode's Preview Canvas? Specifically, how to erase all the Core Data in Canvas created in Canvas' Live Preview?

Example code: This is SwiftUI preview code I am using for Canvas preview.

struct ItemView_Previews: PreviewProvider {
    static var previews: some View {
        let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
        //Test data
        let testItem = Item.init(context: context)
        testItem.name = "Abc"
        return ItemView(filter: false)
            .environment(\.managedObjectContext, context)
    }
}

With this code Canvas shows me testItem, but also item.name of Core Data objects created in Live Preview. I would like to erase Canvas data to not see previously created objects.

Things I have tried: Xcode - Product > Clean Build Folder Xcode - Editor > Canvas > Refresh Canvas Simulator - Device > Erase All Content And Settings...

The last one works as expected for Simulator. I was hoping maybe it will erase Canvas data as well, but it doesn't.

--

Full working example:

ContentView.swift

import SwiftUI
import CoreData

struct ContentView: View {
    
    @Environment(\.managedObjectContext) var managedObjectContext
    @State var paidFilter :Bool? = nil
    
    
    var body: some View {
        
        NavigationView {
            List {
                
                ItemView(filter: paidFilter)
                
            }
            .listStyle(PlainListStyle())
            .navigationTitle(Text("Items"))
            .navigationBarItems(
                trailing:
                    
                    Button(action: {
                        let item = Item(context: self.managedObjectContext)
                        item.name = "Test"
                        
                        do {
                            try self.managedObjectContext.save()
                        }catch{
                            print(error)
                        }
                        
                    }) {
                        Image(systemName: "plus.circle.fill")
                            .font(.title)
                    }
            )
        }
        .navigationViewStyle(StackNavigationViewStyle())
        
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
        return ContentView()
            .environment(\.managedObjectContext, context)
    }
}

ItemView.swift

import SwiftUI

struct ItemView: View {
    @Environment(\.managedObjectContext) var managedObjectContext
    var fetchRequest: FetchRequest<Item>
    var items: FetchedResults<Item> { fetchRequest.wrappedValue }
    
    init(filter: Bool?) {
        fetchRequest = FetchRequest<Item>(entity: Item.entity(), sortDescriptors: [])
    }
    
    var body: some View {
        VStack {
            ForEach(items, id: \.self) {item in
                Text("\(item.name ?? "test123")")
            }
        }
    }
}

struct ItemView_Previews: PreviewProvider {
    static var previews: some View {
        let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
        //Test data
        let testItem = Item.init(context: context)
        testItem.name = "Abc"
        return ItemView(filter: false)
            .environment(\.managedObjectContext, context)
    }
}
Anole answered 2/4, 2021 at 2:28 Comment(5)
Just don't use production persistent container. For Preview and UT it is better to use locally created context with in-memory persistent store (NSInMemoryStoreType). See next for how to set-up code data stack (by using instead addPersistentStoreWithType:NSInMemoryStoreType) developer.apple.com/library/archive/documentation/Cocoa/…Molybdenous
Also this article should be helpful donnywals.com/setting-up-a-core-data-store-for-unit-tests.Molybdenous
Sometimes it's easier to just create a new instance of your app within the preview and then reference the container. MyApp().persistentcontainer.viewContextBeker
Thanks nicksarno and Asperi. I will read more about what you told me. So far I don’t know how to use both techniquesAnole
But putting aside this Core Data issue, is there a Reset button somewhere for Canvas? :)Anole
I
23

Try this,

  • Open terminal
  • Go to your project directory
  • Run this command: xcrun simctl --set previews delete all

This will clear your simulator preview cache data.

Innocent answered 10/10, 2022 at 5:42 Comment(5)
Thank you! It works :) But I think that we don't even need to "Go to project directory".Anole
@mallow, my motive for going to the project directory is just that we clear the cache for that particular project, not all the projects we are working on.Innocent
Ah, so if we run this command in the particular project folder it will reset previews only for this project? I didn't know that. Thanks :)Anole
@mallow, I guess you might be right, can you check this folder ~/Library/Developer/Xcode/UserData/Previews/Simulator Devices before running the command and after running the command. If it clear's the complete folder then we don't need to go to project directory. Simply just run this command in terminal.Innocent
How did you discover this? Annoyed I had to google itHarrelson

© 2022 - 2024 — McMap. All rights reserved.