SwiftUI Preview canvas and Core Data

前端 未结 6 1757
孤独总比滥情好
孤独总比滥情好 2020-12-15 18:59

Preview canvas is is crashing but in simulator everything working fine. I assuming it related to @ObservedObject and @Fetchrequest...

tried solution for here Preview

相关标签:
6条回答
  • 2020-12-15 19:15

    I'm not sure if your try line will work if there is no data.

    let documentTemplate = try! managedObjectContext.fetch(request).first as! Templates
    

    To get mine to work I created a test Item to use. Like this:

    struct DetailView_Previews: PreviewProvider {
        static var previews: some View {
            let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
    //Test data
            let newEvent = Event.init(context: context)
            newEvent.timestamp = Date()
            return DetailView(event: newEvent).environment(\.managedObjectContext, context)
        }
    }
    

    I've also noticed that I needed the .environment(.managedObjectContext, context) code in an earlier tabView that hosted the CoreData views or the preview would fail.

    0 讨论(0)
  • 2020-12-15 19:15

    This answer seems to work in my recent project by replacing the default ContentView_Previews struct, though others are questioning whether it pulls persistent data. Credit goes to @ShadowDES - in the Master/Detail template project in Xcode Beta 7

    I'm able to CRUD anything using Canvas (XCode Version 11.3 (11C29)) and it seems to run flawlessly.

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

    0 讨论(0)
  • 2020-12-15 19:21

    One option is to NOT use Core Data in previews. This is helpful enough to see the UI of what I'm building but I'll still need to use Simulator to test the functionality.

    #if !DEBUG
    // Core Data related code e.g. @FetchRequest
    #endif
    

    What was suggested in Previewing ContentView with CoreData worked for me, Xcode Version 11.0 (11A419c) Mac OS 10.15 Beta (19A558d). My crash logs showed an index error,

    *** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArray0 objectAtIndex:]: index 0 beyond bounds for empty NSArray'

    because there was no data there, so I had to handle this unique "preview" case and that got things working.

    0 讨论(0)
  • 2020-12-15 19:23

    This is my solution.

    I don't want use CoreData in view. I want MVVM style. So you need to mock Core data for display in Canvas view.

    This is an example :

    // View
    struct MyView: View {
        @ObservedObject var viewModel: PreviewViewModel
    }
    
    // View Model
    final class MyViewModel: ObservableObject {
       @Published var repository: RepositoryProtocol // CoreData
    }
    
    // Repository
    protocol RepositoryProtocol { }
    class Repository: RepositoryProtocol { ... } 
    class MockRepository: RepositoryProtocol { ... } // Create a Mock
    
    
    // Init of your view
    // If Canvas use mock
    if ProcessInfo.processInfo.environment["XCODE_RUNNING_FOR_PREVIEWS"] == "1" {
        repository = MockRepository() 
        
    // else App use Repository
    } else {
        repository = Repository.shared
    }
    
    let viewModel = MyViewModel(repository:repository)
    MyViewModel(viewModel: viewModel)
    
    0 讨论(0)
  • 2020-12-15 19:29

    So, if you put some code in an onAppear handler in the preview, it will run on boot. It even live updates as you type!

    struct TemplateEditor_Previews: PreviewProvider {
      static var previews: some View {
        TemplateEditor().environment(\.managedObjectContext, AppDelegate.viewContext).onAppear {
          let entity = GlobalPlaceholders(context: AppDelegate.viewContext)
          entity.name = "abc123"
    
          // Or create more, if you need more example data
    
          try! AppDelegate.viewContext.save()
        }
      }
    }
    

    Note that I've wrapped up my viewContext in a static method on AppDelegate to make access a tiny bit less verbose and easier to remember:

    @UIApplicationMain
    class AppDelegate: UIResponder, UIApplicationDelegate {
      static var persistentContainer: NSPersistentContainer {
        return (UIApplication.shared.delegate as! AppDelegate).persistentContainer
      }
    
      static var viewContext: NSManagedObjectContext {
        return persistentContainer.viewContext
      }
    
    0 讨论(0)
  • 2020-12-15 19:34

    Works for SwiftUI 2 app using the App template

    I also had the previews crash and none of the other solutions were suitable or worked for me.

    What I did was rather than the following:

    struct ContentView_Previews: PreviewProvider {
      
        static var previews: some View {
            return ContentView()
                .environment(
                    \.managedObjectContext,
                    CoreDataManager.context
                )
        }
    }
    

    I fixed it with:

    struct ContentView_Previews: PreviewProvider {
        
        static var previews: some View {
            let context = CoreDataManager.context
    
            /* Optional sample data can be inserted here */
            
            return ContentView()
                .environment(
                    \.managedObjectContext,
                    context
                )
        }
    }
    

    Where CoreDataManager is:

    enum CoreDataManager {
        
        static var context: NSManagedObjectContext {
            persistentContainer.viewContext
        }
        
        static let persistentContainer: NSPersistentContainer = {
            let container = NSPersistentContainer(name: "MyContainerName")
            
            container.loadPersistentStores { description, error in
                guard let error = error else { return }
                fatalError("Core Data error: '\(error.localizedDescription)'.")
            }
            
            return container
        }()
    }
    

    Not exactly sure why this helped, but now it works perfectly. Additionally you can add sample data to this context where I have marked with a comment.

    0 讨论(0)
提交回复
热议问题