Как определить дополнительные методы в протоколе Swift?
возможно ли это в Swift? Если нет, есть ли обходной путь для этого?
15 ответов:
Если вы хотите использовать дополнительные методы, вы должны отметить свой протокол с :
@objc protocol MyProtocol { @objc optional func doSomething() } class MyClass : MyProtocol { // no error }
в противном случае протоколы Swift ведут себя как интерфейсы на других языках OO, где должны быть реализованы все методы, определенные в интерфейсах.
в Swift 2 и далее можно добавить реализации протокола по умолчанию. Это создает новый способ дополнительных методов в протоколах.
protocol MyProtocol { func doSomethingNonOptionalMethod() func doSomethingOptionalMethod() } extension MyProtocol { func doSomethingOptionalMethod(){ // leaving this empty } }
Это не очень хороший способ в создании дополнительных методов протокола, но дает вам возможность использовать структуры в обратных протокола.
Я написал небольшое резюме здесь: http://www.avanderlee.com/swift-2-0/optional-protocol-methods/
другие ответы здесь, связанные с маркировкой протокола как "@objc", не работают при использовании swift-конкретных типов.
struct Info { var height: Int var weight: Int } @objc protocol Health { func isInfoHealthy(info: Info) -> Bool } //Error "Method cannot be marked @objc because the type of the parameter cannot be represented in Objective-C"
чтобы объявить дополнительные протоколы, которые хорошо работают с swift, объявите функции как переменные вместо func.
protocol Health { var isInfoHealthy: (Info) -> (Bool)? { get set } }
а затем реализовать протокол следующим образом
class Human: Health { var isInfoHealthy: (Info) -> (Bool)? = { info in if info.weight < 200 && info.height > 72 { return true } return false } //Or leave out the implementation and declare it as: //var isInfoHealthy: (Info) -> (Bool)? }
вы можете использовать"?"чтобы проверить, была ли реализована функция
func returnEntity() -> Health { return Human() } var anEntity: Health = returnEntity() var isHealthy = anEntity.isInfoHealthy(Info(height: 75, weight: 150))? //"isHealthy" is true
In Swift 3.0
@objc protocol CounterDataSource { @objc optional func increment(forCount count: Int) -> Int @objc optional var fixedIncrement: Int { get } }
Это сэкономит ваше время.
вот конкретный пример с узором делегации.
настройки протокола:
@objc protocol MyProtocol:class { func requiredMethod() optional func optionalMethod() } class MyClass: NSObject { weak var delegate:MyProtocol? func callDelegate() { delegate?.requiredMethod() delegate?.optionalMethod?() } }
установите делегат в класс и реализуйте протокол. Смотрите, что необязательный метод не должен быть реализован.
class AnotherClass: NSObject, MyProtocol { init() { super.init() let myInstance = MyClass() myInstance.delegate = self } func requiredMethod() { } }
одна важная вещь заключается в том, что необязательный метод является необязательным и нуждается в "?- когда звонил. Упомяните второй вопросительный знак.
delegate?.optionalMethod?()
- вам нужно добавить
optional
ключевое слово перед каждым методом.- обратите внимание, однако, что для этого, чтобы работать,ваш протокол должен быть отмечен атрибутом @objc.
- это также означает, что этот протокол будет применим к классам, но не к структурам.
Так как есть некоторые ответы о том, как использовать необязательный модификатор и @objc атрибут чтобы определить дополнительный протокол требований, я приведу пример о том, как использовать расширения протокола define optional protocol.
ниже код Swift 3.*.
/// Protocol has empty default implementation of the following methods making them optional to implement: /// `cancel()` protocol Cancelable { /// default implementation is empty. func cancel() } extension Cancelable { func cancel() {} } class Plane: Cancelable { //Since cancel() have default implementation, that is optional to class Plane } let plane = Plane() plane.cancel() // Print out *United Airlines can't cancelable*
обратите внимание, что методы расширения протокола не могут быть вызваны кодом Objective-C, и хуже того, команда Swift не исправит это. https://bugs.swift.org/browse/SR-492
чтобы проиллюстрировать механику ответа Антуана:
protocol SomeProtocol { func aMethod() } extension SomeProtocol { func aMethod() { print("extensionImplementation") } } class protocolImplementingObject: SomeProtocol { } class protocolImplementingMethodOverridingObject: SomeProtocol { func aMethod() { print("classImplementation") } } let noOverride = protocolImplementingObject() let override = protocolImplementingMethodOverridingObject() noOverride.aMethod() //prints "extensionImplementation" override.aMethod() //prints "classImplementation"
чистый быстрый подход с наследованием протокола:
//Required methods protocol MyProtocol { func foo() } //Optional methods protocol MyExtendedProtocol: MyProtocol { func bar() } class MyClass { var delegate: MyProtocol func myMethod() { (delegate as? MyExtendedProtocol).bar() } }
немного не по теме от первоначального вопроса, но он строится на идее Антуана, и я подумал, что это может кому-то помочь.
вы также можете сделать вычисляемые свойства необязательными для структур с расширениями протокола.
вы можете сделать свойство по Факультативному протоколу
protocol SomeProtocol { var required: String { get } var optional: String? { get } }
реализовать фиктивное вычисленное свойство в расширении протокола
extension SomeProtocol { var optional: String? { return nil } }
и теперь вы можете использовать структуры, которые имеют или не имеют необязательное свойство реализовано
struct ConformsWithoutOptional { let required: String } struct ConformsWithOptional { let required: String let optional: String? }
Я же написал, как это сделать дополнительные свойства в протоколах Swift на моем блоге, который я буду держать в курсе в случае, если все изменится через Swift 2 релизы.
Я думаю, что прежде чем спрашивать как вы можете реализовать дополнительный метод протокола, вы должны спросить почему вы должны реализовать один.
Если мы думаем о протоколах swift как интерфейс в классическом объектно-ориентированном программировании дополнительные методы не имеют большого смысла, и, возможно, лучшим решением было бы создать реализацию по умолчанию или разделить протокол на набор протоколов (возможно, с некоторыми отношениями наследования между ними) для представления возможной комбинации методов в протоколе.
для дальнейшего чтения, см. https://useyourloaf.com/blog/swift-optional-protocol-methods/, что дает отличный обзор по этому вопросу.
вот очень простой пример только для swift классов, а не для структур или перечислений. Обратите внимание, что метод протокола является необязательным, имеет два уровня необязательной цепочки в игре. Также класс, принимающий протокол, нуждается в атрибуте @objc в своем объявлении.
@objc protocol CollectionOfDataDelegate{ optional func indexDidChange(index: Int) } @objc class RootView: CollectionOfDataDelegate{ var data = CollectionOfData() init(){ data.delegate = self data.indexIsNow() } func indexDidChange(index: Int) { println("The index is currently: \(index)") } } class CollectionOfData{ var index : Int? weak var delegate : CollectionOfDataDelegate? func indexIsNow(){ index = 23 delegate?.indexDidChange?(index!) } }
Если вы хотите сделать это в чистом swift, лучший способ-предоставить реализацию по умолчанию particulary, если вы возвращаете тип Swift, например struct С быстрыми типами
пример :
struct magicDatas { var damagePoints : Int? var manaPoints : Int? } protocol magicCastDelegate { func castFire() -> magicDatas func castIce() -> magicDatas } extension magicCastDelegate { func castFire() -> magicDatas { return magicDatas() } func castIce() -> magicDatas { return magicDatas() } }
тогда вы можете реализовать протокол без определяет каждый func
определение
Optional
Protocol
в Swift, вы должны использовать@objc
ключевое слово передProtocol
декларация иattribute
/method
объявление внутри этого протокола. Ниже приведен пример необязательного свойства протокола.@objc protocol Protocol { @objc optional var name:String? } class MyClass: Protocol { // No error }