6

Mam dość dużą aplikację, która ma wiele widoków kolekcji. Większość widoku kolekcji ma te same implementacje dla źródła danych i Delegata układu przepływu (te same rozmiary, marginesy itp.). Próbuję utworzyć pojedynczy protokół, który zapewnia domyślne implementacje UICollectionViewDataSource i UICollectionViewDelegateFlowLayout. Oto mój kod.Rozszerzanie protokołu UICollectionViewDataSource w celu dodania domyślnych implementacji

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 
} 

Problemem jest to, że kompilator narzeka, że ​​MyViewController nie odpowiada UICollectionViewDataSource. Nie powinno tak być, ponieważ wyraźnie mówię, że dodać domyślne implementacje, jeśli typem jest TiledCollectionView.

Czy ktoś może pomóc?

Odpowiedz

5

Wiem, że to nie jest dokładnie to, o co prosiłeś, próbowałem - to nie zadziałało. Teraz szukam możliwej odpowiedzi, bo miał podobną sytuację. Ale mogę zaoferować ci taką opcję, jak ukryć w swoim niestandardowym protokole całą logikę implementacji delegate/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

Wydaje się, że to dobry wzór do dodawania dekoratorów, takich jak te w Pythonie lub Javie. Kontynuuj dodawanie protokołów, które definiują określone zachowanie i pojedyncze wywołanie metody (useProtocolFor ....) mogą dodać to zachowanie. – suparngp

+0

'@ suparngp' Nie wszystkie. Jeśli zadeklarujesz zmienną w protokole ('var handler: CollectionViewProtocolHandler!') - nie możesz jej zaimplementować w rozszerzeniu - musisz więc ręcznie dodać ją do swojej klasy. Przynajmniej nie możesz zbudować swojego projektu bez niego. Byłoby miło, gdyby Apple dodawał deklarację blokowania do protokołu, kiedy dziedziczysz go tak jak w Ruby - możesz więc zobaczyć tam wszystkie rozszerzone zmienne i funkcje i mieć opcję ich przesłonięcia. – katleta3000

4

Spodziewam się, że jest to protokół Objective-C. Objective-C nigdy nie słyszał o rozszerzeniu protokołu. Dlatego nie ma wiedzy, że to rozszerzenie protokołu wstrzykuje dwie funkcje do MyClass. Nie może ich zobaczyć, a jeśli o to chodzi, wymagania protokołu nie są spełnione.

+1

Załóżmy, że masz rację, kiedy próbuję tworzyć domyślną implementację dla UICollectionViewDataSource, pokazuje on błąd, że "kandydat nie jest" @ objc ", ale wymaga tego protokół". Kiedy dodaję atrybut '@ objc' do funkcji protokołu, mówi on, że członkowie rozszerzenia protokołu nie mogą być deklarowani jako' @ objc'. Na przykład mogę zaimplementować UIAlertViewDelegate. – katleta3000

1

Aby dodać, ale modyfikować, co katleta3000 odpowiedział, można ograniczyć protokół stosuje się tylko do „klasy”

CollectionViewProtocol : class

tak, że nie trzeba 'useProtocolForCollectionView:' być mutating

Które następnie sprawia, że ​​nie trzeba tego var reference = self i można po prostu powiedzieć self.userProtocolForCollectionView(collectionView)

Zwłaszcza, jeśli planujesz tylko wdrażanie tego protokołu tylko z NSObject lub klasy ty pes (UIViewController, UICollectionView, itp.)

Powiązane problemy