我最近开始深入研究SwiftUI、Combine和属性包装器的奇妙世界,并努力将@ObservedObject与我为将依赖项注入视图而编写的@Injected属性包装器相结合。大多数时候,我的@Injected包装器工作得很好,但当与@ObservedObject配对来管理我的视图模型时,我收到了";属性类型与"wrappedValue"属性"的类型不匹配;错误">
以下是我的@Injected属性包装器当前的样子:
@propertyWrapper
public struct Injected<Service> {
private var service: Service
public init() {
self.service = assembler.resolver.resolve(Service.self)!
}
public init(name: String? = nil, container: Resolver? = nil) {
// `assembler` here referring to my global Swinject assembler
self.service = container?.resolve(Service.self, name: name) ??
assembler.resolver.resolve(Service.self, name: name)!
}
public var wrappedValue: Service {
get {
return service
}
mutating set {
service = newValue
}
}
public var projectedValue: Injected<Service> {
get {
return self
}
mutating set {
self = newValue
}
}
}
这是我目前的用法:
struct MyModalView: View {
@ObservedObject @Injected var viewModel: MyModalViewModel
var body: some View {
Text("Hello World")
}
}
以这种方式订购包装,我收到:";属性类型"MyModalViewModel"与其包装类型"ObservedObject"的"wrappedValue"属性不匹配;,而MyModalViewModel类确实是从ObservableObject扩展而来的。
如果我翻转包装器,它就会编译,但Swinject试图解析一个包装的ObservedObject类,因为容器只是注册了原始的MyModalViewModel类,所以这个解决方案失败,应用程序崩溃。
同时,通过直接赋值的方式赋值@ObservedObject值:
@ObservedObject var viewModel: MyModalViewModel = assembler.resolver.resolve(MyModalViewModel.self)!
我认为原始代码应该编译,看到@Injected将返回一个符合ObservableObject的包装值,就像@ObservedObject所期望的那样,尽管所有这些对我来说仍然是相当新的,所以我可能缺少了一些东西。如有任何意见,我们将不胜感激。谢谢
对于将来遇到这种情况的人来说,我最终将两个属性包装器组合在一个屋檐下,借用了Resolver项目的实现:
@propertyWrapper
public struct InjectedObject<Service>: DynamicProperty where Service: ObservableObject {
@ObservedObject private var service: Service
public init() {
self.service = assembler.resolver.resolve(Service.self)!
}
public init(name: String? = nil, container: Resolver? = nil) {
self.service = container?.resolve(Service.self, name: name) ??
assembler.resolver.resolve(Service.self, name: name)!
}
public var wrappedValue: Service {
get { return service }
mutating set { service = newValue }
}
public var projectedValue: ObservedObject<Service>.Wrapper {
return self.$service
}
}
使用@InjectedObject注释或Resolver中的服务定位器。而且,别忘了注册你的初始值设定项。
这里的教程