Как показать образец данных в PreviewProvider при использовании FetchRequest

У меня есть такой вид SwiftUI:

import SwiftUI

struct ReView: View {
    @Environment(\.managedObjectContext) var moc
    @FetchRequest(
        entity: Re.entity(),
        sortDescriptors: [
            NSSortDescriptor(keyPath: \Re.name, ascending: false)
        ]
    ) var entities: FetchedResults<Re>
    
    var body: some View {
        NavigationView {
            List(entities, id: \.self) { entity in
                Text(entity.name ?? "Unknown")
            }
        }
    }
}

struct ReView_Previews: PreviewProvider {
    static var previews: some View {
            Group {
               
                ReView()
                    .environment(\.managedObjectContext, PersistentCloudKitContainer.persistentContainer.viewContext)
            }
        }
}

Что я могу сделать, чтобы показать образцы данных в моем предварительном просмотре?

3 ответа

Решение

Вот адаптированный подход (ранее предложенный в /questions/52527490/peredacha-osnovnyih-dannyih-fetchedresults-and-ltt-and-gt-dlya-predvaritelnogo-p/52527497#52527497), протестированный с Xcode 12 / iOS 14

Идея состоит в том, чтобы отделить явное представление + модель от поставщика модели (в данном случае облачной базы данных), чтобы представление можно было спроектировать и протестировать (предварительно просмотреть) с использованием локальной или динамически созданной макетной модели (без использования тяжелого облачного соединения)

truct ReView: View {
    @Environment(\.managedObjectContext) var moc
    @FetchRequest(
        entity: Re.entity(),
        sortDescriptors: [
            NSSortDescriptor(keyPath: \Re.name, ascending: false)
        ]
    ) var entities: FetchedResults<Re>
    
    var body: some View {
        ReEntitiesView(entities: entities)
    }
}

struct ReEntitiesView<Results:RandomAccessCollection>: View where Results.Element == Re {
    let entities: Results

    var body: some View {
        NavigationView {
            List(entities, id: \.self) { entity in
                Text(entity.name ?? "Unknown")
            }
        }
    }
}

struct ReView_Previews: PreviewProvider {
    static let entity = NSManagedObjectModel.mergedModel(from: nil)?.entitiesByName["Re"]

    static var previews: some View {
       let object = Re(entity: entity!, insertInto: nil)
       object.name = "Test Name"

       return ReEntitiesView(entities: [object])
   }
}

Мне удалось создать статический moc для структуры предварительного просмотра, а затем добавить к нему данные по мере необходимости.

Что-то вроде этого:

struct ReView_Previews: PreviewProvider {
    static let moc = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)
    _ = Re(context: moc, mandatoryParam1: "foo" ...)
    _ = Re(context: moc, mandatoryParam1: "bah" ...)
    
    static var previews: some View {
        Group {
            ReView()
                .environment(\.managedObjectContext, moc)
        }
    }
}

Я все еще на первых этапах работы со SwiftUI, поэтому почти наверняка более элегантные способы достижения. Но, по сути, создание тестовых данных - это просто программирование последовательности, которая будет происходить в симуляторе для их создания, поскольку в режиме реального времени это и есть предварительный просмотр.

Обратной стороной является то, что очистка поврежденных тестовых данных также может потребовать некоторых усилий по программированию.

Удачи.

Я просмотрел это руководство сегодня и нашел решение, которым я доволен.

https://www.russellgordon.ca/tutorials/core-data-and-xcode-previews/

Xcode теперь частично решает эту проблему с помощью своего шаблона проекта, когда вы решите включить CoreData. Создан файл Persistence.swift. Если заглянуть внутрь, там static var previewгде вы можете сделать некоторые образцы данных, которые фиксируются в «контексте предварительного просмотра».

В вашем PreviewProvider для представления, которое вы хотите просмотреть, добавьте модификатор к экземпляру представления, который переопределяет manageObjectContext, вместо этого указывая на «контекст предварительного просмотра».

      struct ProductsList_Previews: PreviewProvider {
    static var previews: some View {
        ProductsList()
            .environment(\.managedObjectContext, PersistenceController.preview.container.viewContext)
    }
}

Теперь, когда запускается FetchRequest в моем представлении ProductsList(), он использует «контекст предварительного просмотра», который я использовал в своем переопределении.

Я узнал, как сделать все это, прежде чем найти эту статью сегодня. Препятствие, с которым я столкнулся после, привело меня к статье — как предоставить отдельные примеры моих сущностей для моих предварительных просмотров. Я бы порекомендовал эту статью, если у вас тоже возникли трудности с этим (что в большинстве случаев кажется естественным следующим шагом).

Другие вопросы по тегам