I want to have a protocol that contains a collection of Item
. The goal is for it to not matter if the collection of items
is an array/set/etc, as long as it conforms to Collection
.
protocol Content {
var items: Collection<Item> // This doesn't work, swift doesn't support generic protocol parameters
}
An example use case, where I use Realm to persist Content, but would like to be able to mock data without needing to import Realm:
// Typical usage with Alamofire and Realm
struct RealmArticle: Object, Content {
var items = List<Item>()
}
func fetchContent(completion: (Content?, Error) -> ())) {
session.request(...).responseDecodable { (content: RealmArticle) in
completion(content, nil)
}
}
// Mock without needing to include Realm
func mockFetchContent(completion: (Content?, Error) -> ()) {
completion(MockArticle(items: (0...5).map { Item() }), nil)
}
struct MockArticle: Content {
var items: [Item]
}
My current solution is to use an array in the protocol, and modify the realm model:
protocol Content {
var items: [Item]
}
struct RealmArticle: Object, Content {
var _items = List<Item>()
var items: [Item] { Array(_items) }
}
But this isn't ideal because it loads the entire List
into memory whenever items
is accessed. Is there a better solution or should I take a different approach?
CodePudding user response:
If you can live without the requirement that the element of the collection must be Item
then you can use associatedtype
to make it work with Collection
protocol Content {
associatedtype T: Collection
var items: T { get set }
}
This should be enough to be able to mock as you want.
CodePudding user response:
Why do you need a stand-alone protocol when you could just make this method generic?
func fetchContent<C: Collection>(completion: (Result<C, Error>) -> Void) where C.Iterator.Element == Object {
…
}