Reputation:
I am using a custom class CollectionViewConfigurator
to handle the configuration of my CollectionViewCell in a generic way.
It is working perfectly, here is the sample class :
protocol ConfigurableCell {
static var reuseIdentifier: String { get }
associatedtype DataType
func configure(data: DataType)
}
extension ConfigurableCell {
static var reuseIdentifier: String { return String(describing: Self.self) }
}
protocol CellConfigurator {
static var reuseId: String { get }
func configure(cell: UIView)
var hash: Int { get }
}
class CollectionViewCellConfigurator<CellType: ConfigurableCell, DataType: Hashable>: CellConfigurator where CellType.DataType == DataType, CellType: UICollectionViewCell {
static var reuseId: String { return CellType.reuseIdentifier }
let item: DataType
init(item: DataType) {
self.item = item
}
func configure(cell: UIView) {
(cell as! CellType).configure(data: item)
}
var hash: Int {
return String(describing: CellType.self).hashValue ^ item.hashValue
}
}
extension Int: Diffable {
public var diffIdentifier: AnyHashable {
return self
}
}
NB: I was inspired by a very good article demonstrating the same use for UITableView
. I tried it on my UICollectionView
and it is fantastic.
Anyway, I would like to handle the Drag and Drop within this UICollectionView
.
To do so, if I understand the delegate methods correctly, my items in the UICollectionView need to conform to the NSItemProviderWriting
and NSItemProviderReading
protocol.
When I added the protocol methods, here was the error :
Static stored properties not supported in generic types
I then read this post to understand the error and to try to bypass this.
But I am afraid I am digging into a very complex area of the language.
Can someone explain me how to conform to those protocols with my Class using Generics?
Upvotes: 1
Views: 4467
Reputation: 299565
The linked article is a special case. Generally you don't need to do so much to get what you're trying to do. The only issue is you can't used stored properties. You have to use computed properties. So for instance, if you would have done this (a stored property):
static let writableTypeIdentifiersForItemProvider = ["public.url"]
You just need to do this instead (an equivalent computed property):
static var writableTypeIdentifiersForItemProvider: [String] { return ["public.url"] }
The linked article addresses the case where you need the property to be writable, which means you need to provide storage for it, but this is a rarer case.
In practice, if you want CellConfigurator
to conform to NSItemProviderWriting
, then it would look like:
protocol CellConfigurator: NSItemProviderWriting { ... }
And then CollectionViewCellConfigurator
needs to inherit from NSObject
(in order to get NSObjectProtocol
):
class CollectionViewCellConfigurator<CellType: ConfigurableCell, DataType: Hashable>: NSObject ...
That means that hash
needs to add override
:
override var hash: Int { ... }
And finally, you'd implement the NSItemProviderWriting
methods:
static var writableTypeIdentifiersForItemProvider: [String] { return [...] }
func loadData(withTypeIdentifier typeIdentifier: String, forItemProviderCompletionHandler completionHandler: @escaping (Data?, Error?) -> Void) -> Progress? {
// ...
}
(where ...
is what you want for this type)
The same process goes for NSItemProviderReading
.
Upvotes: 3