2

我最近开始深入研究 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 所期望的那样,尽管所有这些对我来说仍然是相当新的,所以我可能会遗漏一些东西。这里的任何输入将不胜感激。谢谢!!

4

2 回答 2

5

对于将来遇到此问题的任何人,我最终将两个属性包装器组合在一个屋檐下,借用了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
    }
}
于 2020-11-10T20:28:15.163 回答
0

使用 @InjectedObject 注释,或 Resolver 中的服务定位器。而且,不要忘记注册您的初始化程序。

这里有教程

于 2021-11-23T21:39:15.273 回答