如果@EnvironmentObject如何创建通用?

pun*_*bit 4 xcode swiftui xcode11.4

我最近遇到需要编写 a 的 Mock Class,因为它会导致 SwiftUIpreview无法工作。不幸的是,我收到错误:

Property type 'T' does not match that of the 'wrappedValue' property of its wrapper type 'EnvironmentObject'
Run Code Online (Sandbox Code Playgroud)

在视图结构中:

struct ContentView<T>: View {
    @EnvironmentObject var mockFoobar: T
    ...
}
Run Code Online (Sandbox Code Playgroud)

还有错误:

Type of expression is ambiguous without more context
Run Code Online (Sandbox Code Playgroud)

对于预览结构:

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        let mockFoobar: MockFoobar = MockFoobar()
        return ContentView<MockFoobar>()
            .environmentObject(mockFoobar)
    }
}
Run Code Online (Sandbox Code Playgroud)

MockFoobar 类是:

class MockFoobar: ObservableObject {
  ...
}
Run Code Online (Sandbox Code Playgroud)

正如用户@Asperi 善意提供的,按照建议测试了以下内容:

class Foobar: ObservableObject {
    @Published var param: Bool = false
    func start() {
        self.param = true
    }
}

struct MyFoobarView<T: ObservableObject>: View {
    @EnvironmentObject var foobar: T
    
    var body: some View {
        VStack {
            Text("Hello Foobar")
        }
        .onAppear {
            self.foobar.start()
        }
    }
}

struct MyFoobarView_Previews: PreviewProvider {
    static var previews: some View {
        let foobar: Foobar = Foobar()
        return MyFoobarView()
            .environmentObject(foobar)
    }
}
Run Code Online (Sandbox Code Playgroud)

但我收到以下错误(第一个错误.onAppear在 PreviewProvider 中,第二个错误在 PreviewProvider 中):

Cannot call value of non-function type 'Binding<Subject>'

Generic parameter 'T' could not be inferred
Run Code Online (Sandbox Code Playgroud)

Asp*_*eri 8

EnvironmentObject 必须是 ObservableObject,所以这里是修复

struct ContentView<T: ObservableObject>: View {
    @EnvironmentObject var mockFoobar: T
    
    // .. other code here
Run Code Online (Sandbox Code Playgroud)

更新:添加了演示并引入了模型协议

protocol Foobaring {
    var param: Bool { get set }
    func start()
}

class Foobar: ObservableObject, Foobaring {
    @Published var param: Bool = false
    func start() {
        self.param = true
    }
}

struct MyFoobarView<T: ObservableObject & Foobaring>: View {
    @EnvironmentObject var foobar: T

    var body: some View {
        VStack {
            Text("Hello Foobar")
        }
        .onAppear {
            self.foobar.start()
        }
    }
}

struct MyFoobarView_Previews: PreviewProvider {
    static var previews: some View {
        let foobar: Foobar = Foobar()
        return MyFoobarView<Foobar>()
            .environmentObject(foobar)
    }
}
Run Code Online (Sandbox Code Playgroud)