6

У меня есть довольно большое приложение, которое имеет множество видов коллекций. Большинство представлений коллекции имеют одинаковые реализации для источника данных и делегата Layout Flow (те же размеры, поля и т. Д.). Я пытаюсь создать единый протокол, который предоставляет стандартные реализации UICollectionViewDataSource и UICollectionViewDelegateFlowLayout. Вот мой код.Расширение UICollectionViewDataSource Protocol для добавления реализаций по умолчанию

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

Я знаю, что это не совсем то, что вы просили, я попробовал - это не сработало. Теперь ища возможного ответа, потому что имели подобную ситуацию. Но я могу предложить вам такой вариант, как скрыть в вашем пользовательском протоколе всю логику реализации делегата/dataSource.

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-й или классом ф pes (UIViewController, UICollectionView и т. д.)