使用 swinject 注册具有关联类型的协议时出现问题

Posted

技术标签:

【中文标题】使用 swinject 注册具有关联类型的协议时出现问题【英文标题】:Problem registering protocols with associated types using swinject 【发布时间】:2021-05-01 13:00:29 【问题描述】:

我想开发一个使用核心数据和领域的存储库模式的应用程序。我想根据我的需要解决协议。目的是在程序集中注入一个通用的核心数据存储库/领域存储库协议。

这行出现问题 Protocol 'SleepRepositoryProtocol' can only be used as a generic constraint because it has Self or associated type requirements

func assemble(container: Container) 
    container.register(SleepRepositoryProtocol.self)  r in
        CoreDataSleepRepository(persistentContainer:r.resolve(NSPersistentContainer.self)!)
        .inObjectScope(.container)

由于使用通用(关联类型)属性,我无法注入睡眠存储库协议。我该如何解决这个问题?

另外,非常感谢您的回复。它真的帮了我很多。我还有一个问题。

var 存储库:SleepRepositoryProtocol

var items: [SleepEntity]?

private let assembler: Assembler

init(assembler: Assembler) 
    self.assembler = assembler
    
    repository = assembler.resolver.resolve(SleepRepositoryProtocol.self)!

这给了我错误“协议 'SleepRepositoryProtocol' 只能用作通用约束,因为它具有 Self 或关联的类型要求”,我不知道如何解决我的 SleepRepositoryProtocol。

【问题讨论】:

我从未使用过 swinject,但此错误意味着您无法使用具有关联类型的协议来实例化类型。相反,实例化符合它的特定类型。 【参考方案1】:

这个错误很经典:

    container.register(SleepRepositoryProtocol.self)  r in

被禁止,因为SleepRepositoryProtocol 是Protocol with Associated Type。

您需要将assemble(container:) 方法设为通用并以这种方式声明,例如:

func assemble<Repository: SleepRepositoryProtocol>(container: Container, ofType type:Repository) 

但由于它是 Swinject's Assembly Protocol 的一部分,因此不是一个选项,您需要找到另一个放置 Generic Type Constraint 的地方。

在您的情况下,它可以是封闭类型,例如:

class MyClass<Repository: SleepRepositoryProtocol>: Assembly 
    func assemble(container: Container) 
        container.register(Repository.self)  r in
          CoreDataSleepRepository(persistentContainer:r.resolve(NSPersistentContainer.self)!)
        
        .inObjectScope(.container)
    

编辑

你不能只写:

var repository: SleepRepositoryProtocol

一旦您在协议中添加associatedtype,您就可以永远将它像普通类型一样仅作为Generic Type Constraint

如果我用你的其他属性更新MyClass

class MyClass<Repository: SleepRepositoryProtocol>: Assembly 
    var repository: Repository

    var items: [SleepEntity]?

    private let assembler: Assembler

    init(assembler: Assembler) 
        self.assembler = assembler
        
        repository = assembler.resolver.resolve(Repository.self)!
    

    func assemble(container: Container) 
        container.register(Repository.self)  r in
          CoreDataSleepRepository(persistentContainer:r.resolve(NSPersistentContainer.self)!)
        
        .inObjectScope(.container)
    

【讨论】:

非常感谢您的回复。它真的帮了我很多。我对此还有一个问题。这给了我错误,我不知道如何解决我的 SleepRepositoryProtocol。 var repository: RepositoryProtocol var items: [SleepEntity]? private let assembler: Assembler init(assembler: Assembler) self.assembler = assembler repository = assembler.resolver.resolve(RepositoryProtocol.self)! . 很难在评论中阅读。你应该编辑你的问题,或者更好地开始另一个问题 非常感谢您的回复。我已经更新了我的睡眠存储库,并且没有在其上使用泛型。这解决了我的问题,注射效果非常好。 太棒了。我会说,作为一项规则,您应该投票赞成有用的答案并接受为您提供最佳解决方案的答案;)

以上是关于使用 swinject 注册具有关联类型的协议时出现问题的主要内容,如果未能解决你的问题,请参考以下文章

Swinject 容器注册失败

Swinject:生成任何对象的实例(对于未注册的对象、ViewModel 等...)

如何使用 swinject 正确注入依赖项

具有泛型的Swift函数,其中约束是自身符合的协议

Swinject注册UIViewController最佳实践

通过指定类型将“具有关联类型的协议”转换为常规协议