2014-11-23 3 views
1

Я пытаюсь реализовать протокол, который сам наследует несколько протоколов, которые имеют член делегата. Есть ли чистый способ сделать это, не требуя разных имен для делегата каждого протокола?Swift реализует несколько протоколов с делегатом

protocol ProtocolOne { 
    var delegate: ProtocolOneDelegate? 
} 

protocol ProtocolTwo { 
    var delegate: ProtocolTwoDelegate? 
} 

protocol CombinedProtocol: ProtocolOne, ProtocolTwo { 

} 

protocol CombinedDelegate: ProtocolOneDelegate, ProtocolTwoDelegte { 

} 

class ProtocolImpl: CombinedProtocol { 
    // How can I implement delegate here? 
    // I've tried the following options without success: 
    var delegate: CombinedDelegate? 
    var delegate: protocol<ProtocolOneDelegate, ProtocolTwoDelegate>? 
} 
+0

Делегат - это объект, который соответствует протоколу. Я не могу придумать, почему у него есть делегат. – vikingosegundo

+0

@vikingosegundo Я вижу, что делегат принадлежит реализации, а не протоколу. На данный момент я просто удалил свойства делегата из протоколов и только объявил протокол в реализации. Если вы хотите опубликовать это как ответ, я был бы рад принять его. – robhasacamera

ответ

2

В вашем коде delegate является обычным делом. Вы можете иметь несколько протоколов, объявляющих свойство с тем же именем и тем же типом, и иметь класс, прямо или косвенно реализующий его.

Если разные протоколы определяют свойство с тем же именем, но с другим типом, вы не сможете его компилировать, поскольку компилятор будет жаловаться на повторное использование свойства и класса, не подтверждающего один из протоколов.

Возможны 2 варианта решения. Наиболее очевидным является отказ от использования имен, имеющих высокую вероятность использования в других протоколах - delegate - типичный случай. Используйте другое соглашение об именах, такое как protocol1Delegate, dataSourceDelegate, apiCallDelegate и т. Д.

2-е решение состоит из замены свойств на методы. Например:

protocol P1 { 
    func test() -> String? 
} 

protocol P2 { 
    func test() -> Int? 
} 

protocol P3: P1, P2 { 

} 

class Test : P3 { 
    func test() -> String? { return nil } 
    func test() -> Int? { return nil } 
} 

Swift рассматривает функции с тем же списком параметров, но разные типы возврата в качестве перегрузок. Однако обратите внимание, что если в двух протоколах используется одна и та же сигнатура функции (имя, параметры и тип возвращаемого значения), то при реализации в классе вы будете реализовывать эту функцию один раз - это может быть нежелательным поведением в некоторых случаях, но нежелательным в других случаях.

+0

Я действительно хочу, чтобы у меня не было делегатов с разными именами, я сделал это в прошлом, и это не сработало. Кроме того, я не знал, что вы можете перегружать функции возврата в Swift. Однако я попытался перегрузить свойство, и это не сработало. Это означает, что, хотя имя метода внешне было бы таким же, что и внутри, мне все равно понадобятся два свойства с разными именами для их отслеживания. – robhasacamera

2

Решение может заключаться в использовании расширений протокола (отметьте extension Combined). Выгода заключается в том, что Combined объявляет только delegate и oneDelegate и twoDelegate - расчетная кросс-реализация. К сожалению, это требование, чтобы три переменные были выведены из класса, что может быть неудобно.

// MARK: - Delegates protocols 

protocol OneDelegate { 
    func oneDelegate(one: One) 
} 
protocol TwoDelegate { 
    func twoDelegate(two: Two) 
} 
protocol CombinedDelegate: OneDelegate, TwoDelegate { 
    func combinedDelegate(combined: Combined) 
} 


// MARK: - Model protocols 

protocol One: class { 
    var oneDelegate: OneDelegate? { get } 
} 

protocol Two: class { 
    var twoDelegate: TwoDelegate? { get } 
} 

protocol Combined: One, Two { 
    var delegate: CombinedDelegate? { get } 
} 

extension Combined { 
    var oneDelegate: OneDelegate? { 
     return delegate 
    } 
    var twoDelegate: TwoDelegate? { 
     return delegate 
    } 
} 


// MARK: - Implementations 

class Delegate: CombinedDelegate { 
    func oneDelegate(one: One) { 
     print("oneDelegate") 
    } 

    func twoDelegate(two: Two) { 
     print("twoDelegate") 
    } 

    func combinedDelegate(combined: Combined) { 
     print("combinedDelegate") 
    } 
} 

class CombinedImpl: Combined { 
    var delegate: CombinedDelegate? 

    func one() { 
     delegate?.oneDelegate(self) 
    } 

    func two() { 
     delegate?.twoDelegate(self) 
    } 

    func combined() { 
     delegate?.combinedDelegate(self) 
    } 
} 


// MARK: - Usage example 

let delegate = Delegate() 
let protocolImpl = CombinedImpl() 
protocolImpl.delegate = delegate 
protocolImpl.one() 
protocolImpl.two() 
protocolImpl.combined() 
2

Вы должны быть в состоянии объединить их в одном:

var delegate: (ProtocolOneDelegate & ProtocolTwoDelegate)? 

Теперь Вы можете использовать оба протокола.