6

我有一個相當大的應用程序,它有很多集合視圖。大多數集合視圖對數據源和流佈局代表具有相同的實現(相同的大小,邊距等)。我正在嘗試創建一個提供UICollectionViewDataSource和UICollectionViewDelegateFlowLayout的默認實現的協議。這是我的代碼。擴展UICollectionViewDataSource協議以添加默認實現

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,添加默認實現。

有人可以幫忙嗎?

回答

5

我知道這不完全是你問的,我試過 - 它沒有工作。現在尋找可能的答案,因爲有類似的情況。但是我可以爲您提供這樣的選項,以便如何在您的自定義協議中隱藏委託/數據源實現的所有邏輯。

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 
    } 
} 
+0

這似乎是添加裝飾器的好方式,就像Python或Java中的裝飾器一樣。繼續添加定義特定行爲和單個方法調用的協議(useProtocolFor ...)可以添加該行爲。 – suparngp

+0

'@ suparngp'並非如此。如果你在協議中聲明瞭一個變量('var handler:CollectionViewProtocolHandler!') - 你不能在擴展中實現它 - 所以你必須手動將它添加到你的類中。至少你不能在沒有它的情況下建立你的項目。如果Apple向協議添加了聲明塊,那麼當您像Ruby一樣繼承它時會很好,所以您可以在其中看到所有擴展變量和函數,並且可以選擇重寫它們。 – katleta3000

4

我期待的問題是這是一個Objective-C協議。 Objective-C從來沒有聽說過協議擴展。因此它不知道這個協議擴展是向MyClass注入兩個函數。它看不到它們,因此就其而言,協議要求不被滿足。

+1

假設你是對的,當我嘗試爲UICollectionViewDataSource進行默認實現時,他顯示錯誤「候選人不是@ objc',但協議需要它」。當我向協議函數中添加'@ objc'屬性時,它說協議擴展的成員不能被聲明爲'@ objc'。例如,我可以實現UIAlertViewDelegate。 – katleta3000

1

要增加,但修改,什麼katleta3000回答,您可以限制協議只適用於一個「階級」

CollectionViewProtocol : class

,這樣你就不需要'useProtocolForCollectionView:'mutating

然後它使你不需要那var reference = self,你可以說self.userProtocolForCollectionView(collectionView)

特別是如果你只計劃實施這個協議只有NSObject的或class ty pes(UIViewController,UICollectionView等)