Как определить дополнительные методы в протоколе 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
на 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 атрибут чтобы определить дополнительный протокол требований, я приведу пример о том, как использовать расширения протокола определить дополнительный протокол.
ниже кода 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 team не исправит это. 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, лучший способ-предоставить реализацию по умолчанию particullary, если вы возвращаете тип Swift, например структуры С Swift типов
пример :
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
}
