Search code examples
iosswiftswiftuipreview

SwiftUI - too many previews


How to show only 1 Preview for my views? Right now I have a problem with one view: ItemView.swift

After I run Live Preview of ContentView.swift and add few Core Data objects, my ItemView.swift shows Previews for all objects and test data. Having many objects, there are many previews and it slows down Xcode very much.

I have marked in code 2 places that are probably causing problems. I think it's either ForEach or ItemView_Previews struct. I have tried to fix it, but I cannot.

I am using Core Data. And have 1 Entity: Item, with 1 Attribute: date. But I think it's not a Core Data issue.

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.date = Date()
                        
                        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 {
        // I think problem is here
        ForEach(items, id: \.self) {item in
            Text("\(item.date ?? Date())")
        }       
    }
}

struct ItemView_Previews: PreviewProvider {
    static var previews: some View {
        let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
        //Or problem is here - Test data
        let testItem = Item.init(context: context)
        testItem.date = Date()
        return ItemView(filter: false)
            .environment(\.managedObjectContext, context)
    }
}

Solution

  • Replace

    var body: some View {
        // I think problem is here
        ForEach(items, id: \.self) {item in
            Text("\(item.date ?? Date())")
        }       
    }
    

    with

    var body: some View {
    
        /// add VStack here!
        VStack {
            ForEach(items, id: \.self) {item in
                Text("\(item.date ?? Date())")
            }       
        }
    }
    

    Without a VStack or some other container, your body consists of multiple views. This makes Xcode generate a preview for each of them... see here for a similar question.