I have been doing some research into repository pattern as want to use it new project I am working on. However I am having issues getting it working with generics
I have been following this guide here as an example
https://medium.com/@frederikjacques/repository-design-pattern-in-swift-952061485aa
Which does a fairly good job of explaining it. However, the guide leaves off one important detail.. which is using dependancy injection with generics.
In example code, he shows this
class ArticleFeedViewModel {
let articleRepo:ArticleRepository
init( articleRepo:ArticleRepository = WebArticleRepository() ) {
self.articleRepo = articleRepo
}
}
Which works fine if you are not using generics. But once you change ArticleRepository to Repository example... so from
protocol ArticleRepository {
func getAll() -> [Article]
func get( identifier:Int ) -> Article?
func create( article:Article ) -> Bool
func update( article:Article ) -> Bool
func delete( article:Article ) -> Bool
}
to this
protocol Repository {
associatedtype T
func getAll() -> [T]
func get( identifier:Int ) -> T?
func create( a:T ) -> Bool
func update( a:T ) -> Bool
func delete( a:T ) -> Bool
}
I can no longer get the dependancy injection working. So If I were to try re-creating the model shown above.
class WebArticleRepository: Repository {
func getAll() -> [Article] {
return [Article()]
}
func get(identifier: Int) -> Article? {
return Article()
}
func create(a: Article) -> Bool {
return true
}
func update(a: Article) -> Bool {
return false
}
func delete(a: Article) -> Bool {
return true
}
}
class ArticleFeedViewModel {
let articleRepo:Repository
init( articleRepo:Repository = WebArticleRepository() ) {
self.articleRepo = articleRepo
}
}
This no longer works. I now get an error saying
Protocol 'Repository' can only be used as a generic constraint because it has Self or associated type requirements
Any ideas on what I am doing wrong here. It seems adding associatedType causes this to stop working. I would really like to get this functionality working as I want to be able to inject either local or web based repository pattern depending on current state of the app
Any help would be much appriecated
You need to make everything else generic as well:
protocol Repository {
associatedtype RepositoryType
func getAll() -> [RepositoryType]
func get( identifier:Int ) -> RepositoryType?
func create( a:RepositoryType ) -> Bool
func update( a:RepositoryType ) -> Bool
func delete( a:RepositoryType ) -> Bool
}
class WebArticle { }
class WebArticleRepository: Repository {
typealias RepositoryType = WebArticle
func getAll() -> [WebArticle] {
return [WebArticle()]
}
func get(identifier: Int) -> WebArticle? {
return WebArticle()
}
func create(a: WebArticle) -> Bool {
return true
}
func update(a: WebArticle) -> Bool {
return false
}
func delete(a: WebArticle) -> Bool {
return true
}
}
class ArticleFeedViewModel<T : Repository> {
let articleRepo: T
init( articleRepo: T) {
self.articleRepo = articleRepo
}
}
// you cannot have the optional parameter in the init, instead, you can extract the following line to a method
ArticleFeedViewModel(articleRepo: WebArticleRepository())
In Swift you can't use a protocol with associated types as the type of a property/parameter etc. It's supposed to make your code more type-safe.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With