扩展 UICollectionViewDataSource 协议以添加默认实现

Posted

技术标签:

【中文标题】扩展 UICollectionViewDataSource 协议以添加默认实现【英文标题】:Extend UICollectionViewDataSource Protocol to add default implementations 【发布时间】:2015-10-08 09:00:42 【问题描述】:

我有一个相当大的应用程序,它有很多集合视图。大多数集合视图对数据源和流布局委托具有相同的实现(相同的大小、边距等)。我正在尝试创建一个提供 UICollectionViewDataSource 和 UICollectionViewDelegateFlowLayout 的默认实现的协议。这是我的代码。

protocol TiledCollectionView

extension UICollectionViewDataSource where Self: TiledCollectionView
    //default implementation of the 3 methods to load the data ...

extension UICollectionViewDelegateFlowLayout where Self: TiledCollectionView 
    //default implementation for layout methods to set default margins etc...


class MyViewController: UIViewController, TiledCollectionView, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout
    // the rest of the required logic for view controller
    // here I Don't implement any CollectionView methods since I have provided the default implementation already

问题是,编译器抱怨 MyViewController 不符合 UICollectionViewDataSource。这不应该是这种情况,因为我明确表示如果类型是 TiledCollectionView,则添加默认实现。

有人可以帮忙吗?

【问题讨论】:

【参考方案1】:

我知道这与您所要求的不完全一样,我试过了,但没有奏效。现在寻找可能的答案,因为有类似的情况。但是我可以为您提供这样的选项,如何在您的自定义协议中隐藏委托/数据源实现的所有逻辑。

class CollectionViewProtocolHandler: NSObject, UICollectionViewDelegate, UICollectionViewDataSource  

    func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int 
        return 0
    

    func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell 
        return UICollectionViewCell() // only for test
    


protocol CollectionViewProtocol 
    var handler: CollectionViewProtocolHandler! get set
    mutating func useProtocolForCollectionView(collectionView: UICollectionView)


extension CollectionViewProtocol 
    mutating func useProtocolForCollectionView(collectionView: UICollectionView) 
        handler = CollectionViewProtocolHandler()
        collectionView.delegate = handler
        collectionView.dataSource = handler
    


class ViewController: UIViewController, CollectionViewProtocol 
    var handler: CollectionViewProtocolHandler! // CollectionViewProtocol convenience

    override func viewDidLoad() 
        super.viewDidLoad()

        let collectionView = UICollectionView(frame: view.bounds, collectionViewLayout: UICollectionViewFlowLayout())
        collectionView.backgroundColor = .redColor()
        view.addSubview(collectionView)
        var reference = self
        reference.useProtocolForCollectionView(collectionView) // for initialize protocol
    

【讨论】:

这似乎是添加装饰器的好模式,就像 Python 或 Java 中的装饰器一样。继续添加定义特定行为的协议,单个方法调用 (useProtocolFor....) 可以添加该行为。 @suparngp 并非如此。如果您在协议 (var handler: CollectionViewProtocolHandler!) 中声明一个变量 - 您无法在扩展中实现它 - 因此您必须手动将其添加到您的类中。至少你不能没有它来构建你的项目。如果 Apple 在协议中添加声明块,当您像在 Ruby 中一样继承它时,那就太好了 - 这样您就可以看到所有扩展的变量和函数,并可以选择覆盖它们。【参考方案2】:

我预计问题在于这是一个 Objective-C 协议。 Objective-C 从未听说过协议扩展。因此它不知道这个协议扩展正在向 MyClass 注入两个函数。它看不到它们,就它而言,不满足协议要求。

【讨论】:

假设你是对的,当我尝试为 UICollectionViewDataSource 进行默认实现时,他显示错误“候选人不是@objc,但协议需要它”。当我将@objc 属性添加到协议函数时,它表示协议扩展的成员不能声明为@objc。例如,我可以实现 UIAlertViewDelegate。【参考方案3】:

要添加但修改 katleta3000 回答的内容,您可以将协议限制为仅适用于“类”

CollectionViewProtocol : 类

这样您就不需要 'useProtocolForCollectionView:' 成为 mutating

这样你就不需要var reference = self,你可以直接说self.userProtocolForCollectionView(collectionView)

特别是如果您只打算使用 NSObject 或类类型(UIViewController、UICollectionView 等)实现此协议

【讨论】:

以上是关于扩展 UICollectionViewDataSource 协议以添加默认实现的主要内容,如果未能解决你的问题,请参考以下文章

UICollectionView基础

快速致命错误:在展开可选值时意外发现 nil

以编程方式从 collectionView 内的自定义 tableView 中进行 Segue

Kotlin扩展函数总结 ★ ( 超类扩展函数 | 私有扩展函数 | 泛型扩展函数 | 扩展属性 | 定义扩展文件 | infix 关键字用法 | 重命名扩展函数 | 标准库扩展函数 )

Kotlin扩展函数总结 ★ ( 超类扩展函数 | 私有扩展函数 | 泛型扩展函数 | 扩展属性 | 定义扩展文件 | infix 关键字用法 | 重命名扩展函数 | 标准库扩展函数 )

GroovyGroovy 扩展方法 ( 扩展静态方法示例 | 扩展实例方法示例 | 扩展实例方法与扩展静态方法代码相同 )