Hey - I do have such protocols defined:
protocol SessionService {
associatedtype T
}
class SessionServiceDefault : SessionService {
typealias T = Int
}
I cannot find a way to register it properly.
container.register(SessionService.self) { _ in SessionServiceDefault() }
That returns an error:
Protocol 'SessionService' can only be used as a generic constraint because it has Self or associated type requirements
Thanks @grzegorzkrukowski for pointing out the interesting error.
This is a limitation of a protocol with associated types. You get the same error if you try defining a dictionary with that protocol like:
let dict: [SessionService: Any] // Generates the same error.
Swinject also cannot use a protocol with associated types unfortunately馃槩
@grzegorzkrukowski please feel free to reopen this issue or open another issue if you find more problems.
i encountered the same problem. Definitly unresolvable?
@jakubvano Do you know some workaround for this please?
You can paste this directly to the playground in the Swinject project.
The idea is to use boxing and type erasing. It works, however you have to wrap it.
Refer to boxing technique for iOS.
https://www.natashatherobot.com/swift-generics-box/
```import Swinject
protocol Animal {
associatedtype T
}
class AnyTypedAnimal: Animal {
typealias T = Any
}
struct Box
typealias U = T
let objectType: U.Type
let object: U
init(object: U) {
self.object = object
self.objectType = U.self
}
}
final class Cat: Animal {
typealias T = Int
}
final class Mouse: Animal {
typealias T = String
}
let container = Container()
container.register(Box.self) { _ in Box
container.register(Box.self) { _ in Box
let myCatInstance = container.resolve(Box
let mouseInstance = container.resolve(Box
print(container)
Protocols with associated types can directly be referenced only as generics constraints - thus you cannot reference them directly neither in Swinject nor constructor parameters.
As @radimhalfar pointed out, boxing is one way around that.
However in DI cases you would more likely need something like Generalized existentials, which I guess we will have to wait for for quite some time...
Until then I tend to use something like this:
protocol ServiceProtocol {
associatedtype Model
func doSomething(with model: Model)
}
class Service<Model>: ServiceProtocol {
func doSomething(with model: Model) {
fatalError()
}
}
typealias IntService = Service<Int>
final class IntServiceImpl: IntService {
func doSomething(with model: Int) {
// real implementation
}
}
container.autoregister(IntService.self, initializer: IntServiceImpl.init)
It is kinda ugly, doesn't work in all cases and can take a while to get used to, but it is the best I've came up with for tackling this kind of problem.
@radimhalfar @jakubvano Thanks guys 馃憤
Most helpful comment
You can paste this directly to the playground in the Swinject project.
The idea is to use boxing and type erasing. It works, however you have to wrap it.
Refer to
boxingtechnique for iOS.https://www.natashatherobot.com/swift-generics-box/
```import Swinject
protocol Animal {
associatedtype T
}
class AnyTypedAnimal: Animal {
typealias T = Any
}
struct Box {
typealias U = T
}
final class Cat: Animal {
typealias T = Int
}
final class Mouse: Animal {
typealias T = String
}
let container = Container()(object: Cat()) }(object: Mouse()) }
container.register(Box.self) { _ in Box
container.register(Box.self) { _ in Box
let myCatInstance = container.resolve(Box.self).self)
let mouseInstance = container.resolve(Box
print(container)