在通常通过调用数据库获取来处理的 SwiftUI 中设置预览数据的最佳方法是什么?

问题描述

我的应用程序在视图的 .onAppear 方法调用数据库,但我想使用 SwiftUI 的预览功能。有没有办法在预览窗口中模拟或禁用此功能

struct MyView: View {

    @State var dataArray: [Data] = [Data]()
     
    var body: some View {
        vstack { 
             ForEach(dataArray) { data in
                 Text(data.text) 
        }
        .onAppear {
            getData()
        }
    }

    private func getData() {
        someCallToDatabase() { returnedData in
            self.dataArray = returnedData
    }
}

struct MyView_Previews: PreviewProvider {
    
    static var previews: some View {
        MyView()        
    }
}

基本上我想手动传递数据而不被覆盖,或者以某种方式向我的数据库调用者类添加一个扩展,当它知道它只是用于预览时,它会自动设置一些虚拟数据。

谢谢一束,仰卧起坐!

解决方法

通过使用某种依赖注入,您可以确保有一个类/对象负责执行可以模拟的数据库调用。其中一个版本可能是使用 @Envrionment 发送一个对象来处理数据库调用:


struct ApiData : Identifiable {
    var id = UUID()
    var text : String
}

protocol DatabaseManager {
    func someCallToDatabase(_ callback : ([ApiData]) -> Void)
}

class RealDatabaseManager : DatabaseManager {
    func someCallToDatabase(_ callback: ([ApiData]) -> Void) {
        callback([]) //do real database call here
    }
}

class MockDatabaseManager : DatabaseManager {
    func someCallToDatabase(_ callback: ([ApiData]) -> Void) {
        callback([])
    }
}

private struct DatabaseEnvironmentKey: EnvironmentKey {
    static let defaultValue : DatabaseManager = RealDatabaseManager()
}

extension EnvironmentValues {
    var databaseManager : DatabaseManager {
        get { self[DatabaseEnvironmentKey.self] }
        set { self[DatabaseEnvironmentKey.self] = newValue }
    }
}

struct MyView: View {

    @State var dataArray: [ApiData] = [ApiData]()
    @Environment(\.databaseManager) private var databaseManager : DatabaseManager
     
    var body: some View {
        VStack {
             ForEach(dataArray) { data in
                 Text(data.text)
             }
        }
        .onAppear {
            getData()
        }
    }

    func getData() {
        databaseManager.someCallToDatabase { returnedData in
            self.dataArray = returnedData
        }
    }
}

struct MyView_Previews: PreviewProvider {
    static var previews: some View {
        MyView().environment(\.databaseManager,MockDatabaseManager())
    }
}

当然,您需要确保在非预览视图中,您还在父视图中使用 .environment(...)真实 数据库管理器向下传递到视图层次结构视图,因此需要对现有代码稍作修改。