【问题标题】:Extend UICollectionViewDataSource Protocol to add default implementations扩展 UICollectionViewDataSource 协议以添加默认实现
【发布时间】: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,则添加默认实现。

有人可以帮忙吗?

【问题讨论】:

    标签: swift uicollectionview swift-extensions swift-protocols protocol-extension


    【解决方案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 等)实现此协议

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多