【问题标题】:UICollectionView delegate methods never called when inheriting from a generic class从泛型类继承时从不调用 UICollectionView 委托方法
【发布时间】:2020-10-04 10:00:41
【问题描述】:

我有一个名为GenericView<Key: Equatable> 的通用类,它符合UICollectionViewDelegateFlowLayout 协议并拥有一个collectionview。然后我有一个NewView 类继承自GenericView<Key: Equatable>

问题是,在NewView 类中实现的委托方法如果在GenericView<Key: Equatable> 中不存在,则永远不会被调用。 UIScrollView 委托方法也永远不会被调用,除非它们具有 @objc 前缀。但是,@objc 前缀并不能解决 UICollectionView 委托问题。

简单代码:

// MARK: - Generic Class

class GenericView<Key: Equatable>: UIView, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {

    var key: Key?

    var collectionView = UICollectionView(frame: .zero, collectionViewLayout: UICollectionViewFlowLayout())

    override init(frame: CGRect) {
        super.init(frame: frame)
        // Constraint collection view.
        collectionView.translatesAutoresizingMaskIntoConstraints = false
        addSubview(collectionView)
        NSLayoutConstraint.activate([
            collectionView.leadingAnchor.constraint(equalTo: leadingAnchor),
            collectionView.topAnchor.constraint(equalTo: topAnchor),
            collectionView.trailingAnchor.constraint(equalTo: trailingAnchor),
            collectionView.bottomAnchor.constraint(equalTo: bottomAnchor)
        ])
        // Set delegate and data source.
        collectionView.delegate  = self
        collectionView.dataSource = self
        collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "Cell")
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return 100
    }

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath)
        cell.contentView.backgroundColor = .blue
        return cell
    }

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        return CGSize(width: 100, height: 100)
    }

    func scrollViewWillBeginDecelerating(_ scrollView: UIScrollView) {
        print("generic class: \(#function)")
    }

    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        print("generic class: \(#function)")
    }
}

// MARK: - SubClass

class NewView: GenericView<String> {

    // called
    override func scrollViewWillBeginDecelerating(_ scrollView: UIScrollView) {
        print("new class: \(#function)")
    }

    // called
    override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        print("new class: \(#function)")
    }

    // called
    @objc func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
        print("new class: \(#function)")
    }

    // not called
    func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
        print("new class: \(#function)")
    }

    // not called
    func collectionView(_ collectionView: UICollectionView, didHighlightItemAt indexPath: IndexPath) {
        print("new class: \(#function)")
    }

    // not called
    @objc func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
        print("new class: \(#function)")
    }
}

虽然UICollectionViewDelegateFlowLayout继承自UIScrollViewDelegate,但在上述代码中它们的行为不同。

我发现这个:https://bugs.swift.org/browse/SR-2817。该错误是在 2016 年报告的。

看来这不是UICollectionView的问题,而是Swift和Objective-C交互中存在的问题。

我想知道这是否是一个将来会解决的问题,或者它是一个特性,我应该阻止以这种方式编写代码。这真的让我很困惑,浪费了很多时间。泛型类型是一个好主意,在编程中被广泛使用。

【问题讨论】:

    标签: ios swift xcode uicollectionview


    【解决方案1】:

    问题是UICollectionViewDelegateFlowLayout 委托被设置为GenericView 的代表。但是NewView 有另一组方法没有被collectionViewUICollectionViewDelegateFlowLayout 确认。要使其工作,您需要在 NewView 中的 UICollectionViewDelegateFlowLayout 方法前面添加前缀 override

    【讨论】:

    • override 如果我首先在GenericView 中实现UICollectionViewDelegateFlowLayout 方法,然后在NewView 中覆盖它们,那么override 关键字确实有效。但是,我没有在GenericView 中实现委托方法,而是尝试在NewView 中直接实现委托方法。在这种情况下,滚动视图委托方法在具有 @objc 前缀时被调用。但是,集合视图委托方法永远不会被调用,无论它们是否具有 @objc 前缀。由于UICollectionViewDelegateFlowLayout 继承自UIScrollViewDelegate,我认为它们应该具有相同的行为。
    • 如果不调用super.cellForItemAt,则不会调用超级方法。在这种情况下,覆盖实际上就像是新编写的方法一样工作。
    猜你喜欢
    • 1970-01-01
    • 2012-09-22
    • 2012-12-31
    • 2019-07-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多