itosun
itosun

Reputation: 11

Problem registering protocols with associated types using swinject

I wanted to develop an application which uses repository patterns using core data and realm. I want to resolve protocol according to my needs. Purpose is to inject a generic core data repository / realm repository protocol in the assembly.

Problem occurs on this line saying 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)
}

I am unable to inject sleep repository protocol because of using generic (associated type) properties. How can I solve this problem?

Additionally,thank you very much for your response. It really helped me a lot. I have one more issue with this.

var repository: SleepRepositoryProtocol

var items: [SleepEntity]?

private let assembler: Assembler

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

This gives me error "Protocol 'SleepRepositoryProtocol' can only be used as a generic constraint because it has Self or associated type requirements" and I don't know how to resolve my SleepRepositoryProtocol.

Upvotes: 1

Views: 555

Answers (1)

AnderCover
AnderCover

Reputation: 2661

This error is a classic:

    container.register(SleepRepositoryProtocol.self) { r in

is forbidden because SleepRepositoryProtocol is a Protocol with Associated Type.

what you would need is for the assemble(container:) method to be generic and declared this way for example:

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

but since it's part of Swinject's Assembly Protocol it is not an option and you need to find another place to put the Generic Type Constraint.

In your case it can be the enclosing type eg.:

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

Edit

you cannot just write :

var repository: SleepRepositoryProtocol

Once you add associatedtype in you protocol you can never use it like a normal type, only as a Generic Type Constraint

So if I update MyClass with your other properties:

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)
    }
}

Upvotes: 1

Related Questions