2016-07-26 9 views
2

Я пытаюсь переопределить метод экземпляра из расширения протокола, и у меня проблемы.Как переопределить метод экземпляра из расширения протокола в Swift?

Для контекста я создаю приложение iOS с множеством различных UICollectionView. Эти представления получают данные из разных баз данных (требующие разных функций обратного вызова) и имеют очень разные макеты. Поскольку любая комбинация (база данных, макет) возможна, трудно создать хорошую иерархию классов ООП без массивного дублирования кода.

У меня возникла идея поместить функции макета (главным образом те, которые определены в протоколе UICollectionViewDelegateFlowLayout) в расширения протокола, поэтому я могу украсить данный подкласс UICollectionView протоколом, который расширен для реализации всех соответствующих функций макета, но я имея трудное время. Суть проблемы содержится в приведенном ниже коде.

class Base { 
    func speak(){ 
     print("Base") 
    } 
} 

class SubA: Base, ProtocolA {} 

class SubB: Base, MyProtocolB {} 

protocol MyProtocolA{ 
    func speak() 
} 

protocol MyProtocolB{ 
    func speak() 
} 

extension MyProtocolA{ 
    func speak(){ 
     print("A")   
    } 
} 

extension MyProtocolA{ 
    func speak(){ 
     print("B")   
    } 
} 

let suba = SubA() 
suba.speak() // prints "Base", I want it to print "A" 

let subb = SubB() 
subb.speak() // prints "Base", I want it to print "B" 

Мысли?

+2

«У меня возникла идея поместить функции макета (в основном те, которые определены в протоколе UICollectionViewDelegateFlowLayout) в расширения протокола« Забудьте эту идею. Objective-C никогда не вызовет реализацию из расширения протокола, поскольку Objective-C не может _see_ расширять протокол. Это функция Swift. – matt

+0

@matt Этот вопрос не о Obj-C, хотя, не так ли? –

+2

@TimVermeulen Да, это так. Речь идет о методах делегирования Objective-C в расширениях протокола Swift. – matt

ответ

2

Реализации по умолчанию в протоколах вызывается только в том случае, если класс, соответствующий этим протоколам, не реализует этот метод. Методы классов переопределяют реализацию протоколов по умолчанию, а не наоборот.

Как правило, вы могли бы сделать что-то вроде:

protocol MyProtocolA { 
    func speak() 
} 

protocol MyProtocolB { 
    func speak() 
} 

extension MyProtocolA { 
    func speak() { 
     print("A")   
    } 
} 

extension MyProtocolB { 
    func speak() { 
     print("B")   
    } 
} 

class SubA: MyProtocolA {} 

class SubB: MyProtocolB {} 

let suba = SubA() 
suba.speak() // prints "A" 

let subb = SubB() 
subb.speak() // prints "B" 

Но если вы

class SubC: MyProtocolA { 
    func speak(){ 
     print("C") 
    } 
} 

let subc = SubC() 
subc.speak() // prints "C" 

Честно говоря, как вы смотрите на это, использование Base совершенно лишними в этом примере, поэтому я удалил его. Очевидно, что если вам нужен подкласс от Base по другим причинам, не стесняйтесь. Но ключевым моментом является то, что реализации по умолчанию протокола не переопределяют реализацию классов, а наоборот.

+0

Отличный ответ, спасибо Роб. Последующее наблюдение: как это будет реализовано тогда без повторного использования кода? Под «этим» я подразумеваю любой сценарий смешивания и сопоставления с двумя переменными, как здесь (где любой подкласс должен реализовывать функциональность на основе как своей базы данных, так и макета). Функциональность не поддается иерархической структуре. –

+0

Я не буду за тобой. Можете ли вы дать практический пример того, что вы имеете в виду? – Rob

+0

Итак, у моего приложения есть UICollectionViews: a) имеют различные макеты и б) захватывают свои данные из разных баз данных. Более конкретно, у меня есть макет «icon» и макет «detail», каждый из которых переопределяет cellForItemAtIndexPath и множество методов UICollectionViewDelegateFlowLayout. Однако у меня также есть две базы данных, и необходим другой код, в зависимости от того, из какой базы данных CollectionView извлекает данные. Таким образом, любая комбинация типа {Database 1, Database2} x {Icon, Detail} нуждается в собственном подклассе. Но вы не можете этого сделать без дублирования кода –

Смежные вопросы