简体   繁体   中英

iOS - How to conform to NSItemProviderWriting and NSItemProviderReading protocol on class using Generics

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?

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 .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM