1

The goal is to dequeue cell like

 let cell = CustomCollectionViewCell.dequeueReusable(collectionView, for: indexPath)

I'm trying like

class func dequeueReusable<T: UICollectionViewCell>(_ collectionView: UICollectionView, for indexPath: IndexPath) -> T {
    return collectionView.dequeueReusableCell(withReuseIdentifier: self.reuseID, for: indexPath) as! T
}

But it returns UICollectionViewCell, not CustomCollectionViewCell.

How to achieve this?

Dávid Pásztor
  • 51,403
  • 9
  • 85
  • 116
Nike Kov
  • 12,630
  • 8
  • 75
  • 122
  • `self.reuseID` cannot compile in a `class` function, so you should [edit] your question to include your actual code in the form of a [mcve]. Btw it would make more sense to define this method as an extension on `UICollectionView` and pass in the `UICollectionViewCell` subclass type as a generic input argument. – Dávid Pásztor Feb 15 '19 at 15:05
  • Recommend taking a look into https://github.com/AliSoftware/Reusable. It does the thing you want. (If I didn't misunderstand your question) – mrfour Feb 15 '19 at 15:20
  • A protocol extension with associated type might be the better choice, – vadian Feb 15 '19 at 15:32
  • @vadian: Like this https://stackoverflow.com/a/34004264/1187415 ? :) – Martin R Feb 15 '19 at 15:38
  • @MartinR Yes, something like that – vadian Feb 15 '19 at 16:00
  • Related discussion in the Swift forum: https://forums.swift.org/t/workarounds-for-self-in-classes/15754 . – Martin R Feb 15 '19 at 16:26

1 Answers1

1

Your call to dequeueReusable never requires any particular type for T, so the most general is selected. The type you want, however, is Self (the type of the current subclass).

The natural (but slightly wrong) way to write this would be:

class func dequeueReusable(_ collectionView: UICollectionView, 
                           for indexPath: IndexPath) -> Self {
    return collectionView.dequeueReusableCell(withReuseIdentifier: self.reuseID,
                                                              for: indexPath) as! Self
}

I honestly don't know why this doesn't work. Self can't be used in the as! Self construct. It can, however, be tricked into working with a generic wrapper:

func cast<T>(_ value: Any) -> T { return value as! T }

With that, you get the working version:

class func dequeueReusable(_ collectionView: UICollectionView,
                           for indexPath: IndexPath) -> Self {
    return cast(collectionView.dequeueReusableCell(withReuseIdentifier: self.reuseID, 
                                                   for: indexPath))
}
Rob Napier
  • 286,113
  • 34
  • 456
  • 610
  • 1
    `unsafeDowncast(..., to: self)` would be an alternative: https://stackoverflow.com/a/33200426/1187415. – Martin R Feb 15 '19 at 15:21
  • Thank you; I knew there was some other solution I'd seen somewhere. And actually this is better Swift. I think this should dupe that one. – Rob Napier Feb 15 '19 at 15:22