Rxswift: UICollectionViewDelegateFlowLayout delegate is not called

Created on 16 Oct 2016  路  1Comment  路  Source: ReactiveX/RxSwift

Short description of the issue:

I'm trying to use RXSwift in my UICollectionView Source. I've already setup the rx.setDelegate(self) to my class but the methods like

func collectionView(collectionView: UICollectionView,
                        layout collectionViewLayout: UICollectionViewLayout,
                        sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize

is never called.

Self contained code example that reproduces the issue:

My Datasource Class using RX implementation

class ProductDataSource: NSObject, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout {

    private let products: Variable<Array<CartProduct>>

    private let bag = DisposeBag()
    private let collectionView: UICollectionView

    init(_ collectionView: UICollectionView, products: Variable<Array<CartProduct>>) {
        self.collectionView = collectionView
        self.products       = products
        super.init()
    }

    func prepareSource() {

        collectionView.rx.setDelegate(self)
                         .addDisposableTo(bag)

        products.asObservable()
                .bindTo(collectionView.rx.items) { (tableView, row, element) in
                    let indexPath = IndexPath(row: row, section: 0)
                    let cell = self.collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! BaseProductCell

                    cell.layer.borderWidth  = 1
                    cell.layer.borderColor  = UIColor.whiteSmokeColor.cgColor
                    cell.layer.cornerRadius = 5

                    cell.test.text = "\(row) :: \(element.product.id)"
                    return cell
                }
                .addDisposableTo(bag)
    }

}

Calling in controller:

    private var source: ProductDataSource?

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        source = ProductDataSource(self.collection, products: SharedCart.shared.products)
        source?.prepareSource()

        self.touched(BaseProduct())
    }

Extension for delegate methods:

extension ProductDataSource {
    // Collection view flow layout setup

    func collectionView(collectionView: UICollectionView,
                        layout collectionViewLayout: UICollectionViewLayout,
                        sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {

        let screenSize              = UIScreen.main.bounds
        let screenWidth             = screenSize.width
        let cellSquareSize: CGFloat = (screenWidth / 2.0) - 10

        return CGSize.init(width: cellSquareSize, height: 240.0)
    }

    func collectionView(collectionView: UICollectionView,
                        layout collectionViewLayout: UICollectionViewLayout,
                        insetForSectionAtIndex section: Int) -> UIEdgeInsets {
        return UIEdgeInsetsMake(5, 5, 5, 5)
    }

    func collectionView(collectionView: UICollectionView,
                        layout collectionViewLayout: UICollectionViewLayout,
                        minimumLineSpacingForSectionAtIndex section: Int) -> CGFloat {
        return 5
    }

    func collectionView(collectionView: UICollectionView,
                        layout collectionViewLayout: UICollectionViewLayout,
                        minimumInteritemSpacingForSectionAtIndex section: Int) -> CGFloat {
        return 5
    }
}

Xcode version:

v8.0

Expected outcome:

Delegate methods should be called. There are already 10+ products in my list.

What actually happens:
Delegate methods are not called.

Installation method:

  • [x] CocoaPods
  • [ ] Carthage
  • [ ] Git submodules

I have multiple versions of Xcode installed:
(so we can know if this is a potential cause of your issue)

  • [ ] yes (which ones)
  • [x] no

Level of RxSwift knowledge:
(this is so we can understand your level of knowledge
and formulate the response in an appropriate manner)

  • [x] just starting
  • [ ] I have a small code base
  • [ ] I have a significant code base

Most helpful comment

I've resolved this issue. Method definitions were not compatible with Swift 3.

New Extension looks like:

extension ProductDataSource {

    @objc(collectionView:layout:sizeForItemAtIndexPath:)
    func collectionView(_ collectionView: UICollectionView,
                        layout collectionViewLayout: UICollectionViewLayout,
                        sizeForItemAt indexPath: IndexPath) -> CGSize {

        let screenSize              = UIScreen.main.bounds
        let screenWidth             = screenSize.width
        let cellSquareSize: CGFloat = (screenWidth / 2.0) - 10

        return CGSize.init(width: cellSquareSize, height: 240.0)
    }

    @objc(collectionView:layout:insetForSectionAtIndex:)
    func collectionView(_ collectionView: UICollectionView,
                        layout collectionViewLayout: UICollectionViewLayout,
                        insetForSectionAt section: Int) -> UIEdgeInsets {
        return UIEdgeInsetsMake(5, 5, 5, 5)
    }

    @objc(collectionView:layout:minimumLineSpacingForSectionAtIndex:)
    func collectionView(_ collectionView: UICollectionView,
                        layout collectionViewLayout: UICollectionViewLayout,
                        minimumLineSpacingForSectionAt section: Int) -> CGFloat {
        return 5
    }

    @objc(collectionView:layout:minimumInteritemSpacingForSectionAtIndex:)
    func collectionView(_ collectionView: UICollectionView,
                        layout collectionViewLayout: UICollectionViewLayout,
                        minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
        return 5
    }
}

>All comments

I've resolved this issue. Method definitions were not compatible with Swift 3.

New Extension looks like:

extension ProductDataSource {

    @objc(collectionView:layout:sizeForItemAtIndexPath:)
    func collectionView(_ collectionView: UICollectionView,
                        layout collectionViewLayout: UICollectionViewLayout,
                        sizeForItemAt indexPath: IndexPath) -> CGSize {

        let screenSize              = UIScreen.main.bounds
        let screenWidth             = screenSize.width
        let cellSquareSize: CGFloat = (screenWidth / 2.0) - 10

        return CGSize.init(width: cellSquareSize, height: 240.0)
    }

    @objc(collectionView:layout:insetForSectionAtIndex:)
    func collectionView(_ collectionView: UICollectionView,
                        layout collectionViewLayout: UICollectionViewLayout,
                        insetForSectionAt section: Int) -> UIEdgeInsets {
        return UIEdgeInsetsMake(5, 5, 5, 5)
    }

    @objc(collectionView:layout:minimumLineSpacingForSectionAtIndex:)
    func collectionView(_ collectionView: UICollectionView,
                        layout collectionViewLayout: UICollectionViewLayout,
                        minimumLineSpacingForSectionAt section: Int) -> CGFloat {
        return 5
    }

    @objc(collectionView:layout:minimumInteritemSpacingForSectionAtIndex:)
    func collectionView(_ collectionView: UICollectionView,
                        layout collectionViewLayout: UICollectionViewLayout,
                        minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
        return 5
    }
}
Was this page helpful?
0 / 5 - 0 ratings

Related issues

jaumard picture jaumard  路  3Comments

RafaelPlantard picture RafaelPlantard  路  3Comments

tyregor picture tyregor  路  3Comments

angerman picture angerman  路  3Comments

gaudecker picture gaudecker  路  3Comments