Swift Language Conceptos básicos del protocolo


Ejemplo

Acerca de los protocolos

Un protocolo especifica inicializadores, propiedades, funciones, subíndices y tipos asociados requeridos de un tipo de objeto Swift (clase, estructura o enumeración) conforme al protocolo. En algunos idiomas, ideas similares para especificaciones de requisitos de objetos subsiguientes se conocen como 'interfaces'.

Un protocolo declarado y definido es un tipo, en sí mismo, con una firma de sus requisitos establecidos, algo similar a la manera en que las funciones Swift son un tipo basado en su firma de parámetros y devoluciones.

Las especificaciones de Swift Protocol pueden ser opcionales, explícitamente requeridas y / o dadas implementaciones predeterminadas a través de una instalación conocida como Protocol Extensions. Un tipo de objeto Swift (clase, estructura o enumeración) que desee ajustarse a un Protocolo que se completa con Extensions para todos sus requisitos específicos solo debe indicar su deseo de cumplir con la conformidad total. La facilidad de implementación predeterminada de las Extensiones de Protocolo puede ser suficiente para cumplir con todas las obligaciones de conformidad con un Protocolo.

Los Protocolos pueden ser heredados por otros Protocolos. Esto, junto con las Extensiones de protocolo, significa que los Protocolos pueden y deben considerarse como una característica importante de Swift.

Los protocolos y extensiones son importantes para realizar los objetivos y enfoques más amplios de Swift para la flexibilidad del diseño de programas y los procesos de desarrollo. El propósito principal declarado de la capacidad de Protocolo y Extensión de Swift es facilitar el diseño compositivo en la arquitectura y el desarrollo del programa. Esto se conoce como Programación Orientada al Protocolo. Los viejos crustadores consideran esto superior a un enfoque en el diseño OOP.

Los protocolos definen interfaces que pueden ser implementadas por cualquier estructura , clase o enumeración :

protocol MyProtocol {
    init(value: Int)                      // required initializer
    func doSomething() -> Bool            // instance method
    var message: String { get }           // instance read-only property
    var value: Int { get set }            // read-write instance property
    subscript(index: Int) -> Int { get }  // instance subscript
    static func instructions() -> String  // static method
    static var max: Int { get }           // static read-only property
    static var total: Int { get set }     // read-write static property
}

Las propiedades definidas en los protocolos deben anotarse como { get } o { get set } . { get } significa que la propiedad debe ser obtenible, y por lo tanto, se puede implementar como cualquier tipo de propiedad. { get set } significa que la propiedad debe ser configurable así como también gettable.

Una estructura, clase o enumeración puede ajustarse a un protocolo:

struct MyStruct : MyProtocol {
    // Implement the protocol's requirements here
}
class MyClass : MyProtocol {
    // Implement the protocol's requirements here
}
enum MyEnum : MyProtocol {
    case caseA, caseB, caseC
    // Implement the protocol's requirements here
}

Un protocolo también puede definir una implementación predeterminada para cualquiera de sus requisitos a través de una extensión :

extension MyProtocol {
    
    // default implementation of doSomething() -> Bool
    // conforming types will use this implementation if they don't define their own
    func doSomething() -> Bool {
        print("do something!")
        return true
    }
}

Se puede usar un protocolo como tipo , siempre que no tenga requisitos de tipo associatedtype :

func doStuff(object: MyProtocol) {
    // All of MyProtocol's requirements are available on the object
    print(object.message)
    print(object.doSomething())
}

let items : [MyProtocol] = [MyStruct(), MyClass(), MyEnum.caseA]

También puede definir un tipo abstracto que se ajuste a múltiples protocolos:

3.0

Con Swift 3 o superior, esto se hace separando la lista de protocolos con un signo ( & ):

func doStuff(object: MyProtocol & AnotherProtocol) {
    // ...
}

let items : [MyProtocol & AnotherProtocol] = [MyStruct(), MyClass(), MyEnum.caseA]
3.0

Las versiones anteriores tienen un protocol<...> sintaxis protocol<...> donde los protocolos son una lista separada por comas entre los corchetes angulares <> .

protocol AnotherProtocol {
    func doSomethingElse()
}

func doStuff(object: protocol<MyProtocol, AnotherProtocol>) {
    
    // All of MyProtocol & AnotherProtocol's requirements are available on the object
    print(object.message)
    object.doSomethingElse()
}

// MyStruct, MyClass & MyEnum must now conform to both MyProtocol & AnotherProtocol
let items : [protocol<MyProtocol, AnotherProtocol>] = [MyStruct(), MyClass(), MyEnum.caseA]

Los tipos existentes se pueden ampliar para ajustarse a un protocolo:

extension String : MyProtocol {
    // Implement any requirements which String doesn't already satisfy
}