Как определить дополнительные методы в протоколе 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
}