¿Es posible en Swift? Si no es así, ¿hay alguna solución para hacerlo?
¿Es posible en Swift? Si no es así, ¿hay alguna solución para hacerlo?
Respuestas:
protocol MyProtocol {
func doSomething()
}
extension MyProtocol {
func doSomething() {
/* return a default value or just leave empty */
}
}
struct MyStruct: MyProtocol {
/* no compile error */
}
Ventajas
No hay tiempo de ejecución de Objective-C involucrado (bueno, al menos no explícitamente). Esto significa que puede conformar estructuras, enumeraciones y no NSObject
clases. Además, esto significa que puede aprovechar el potente sistema de genéricos.
Siempre puede estar seguro de que se cumplen todos los requisitos al encontrar tipos que se ajustan a dicho protocolo. Siempre es una implementación concreta o una predeterminada. Así es como se comportan las "interfaces" o los "contratos" en otros idiomas.
Desventajas
Para los no Void
requisitos, debe tener un valor predeterminado razonable , que no siempre es posible. Sin embargo, cuando encuentre este problema, significa que tal requisito realmente no debería tener una implementación predeterminada o que cometió un error durante el diseño de la API.
No puede distinguir entre una implementación predeterminada y ninguna implementación , al menos sin abordar ese problema con valores de retorno especiales. Considere el siguiente ejemplo:
protocol SomeParserDelegate {
func validate(value: Any) -> Bool
}
Si proporciona una implementación predeterminada que solo regresa true
, está bien a primera vista. Ahora, considere el siguiente pseudocódigo:
final class SomeParser {
func parse(data: Data) -> [Any] {
if /* delegate.validate(value:) is not implemented */ {
/* parse very fast without validating */
} else {
/* parse and validate every value */
}
}
}
No hay forma de implementar tal optimización: no puede saber si su delegado implementa un método o no.
Aunque hay varias maneras diferentes de superar este problema (usando cierres opcionales, diferentes objetos delegados para diferentes operaciones, por nombrar algunos), ese ejemplo presenta el problema claramente.
@objc optional
.@objc protocol MyProtocol {
@objc optional func doSomething()
}
class MyClass: NSObject, MyProtocol {
/* no compile error */
}
Ventajas
Desventajas
Limita severamente las capacidades de su protocolo al requerir que todos los tipos conformes sean compatibles con Objective-C. Esto significa que solo las clases que heredan de NSObject
pueden ajustarse a dicho protocolo. Sin estructuras, sin enumeraciones, sin tipos asociados.
Siempre debe verificar si se implementa un método opcional llamando o verificando opcionalmente si el tipo conforme lo implementa. Esto podría introducir una gran cantidad de repeticiones si llama a métodos opcionales con frecuencia.
respondsToSelector
?
optional func doSomething(param: Int?)
En Swift 2 y en adelante, es posible agregar implementaciones predeterminadas de un protocolo. Esto crea una nueva forma de métodos opcionales en los protocolos.
protocol MyProtocol {
func doSomethingNonOptionalMethod()
func doSomethingOptionalMethod()
}
extension MyProtocol {
func doSomethingOptionalMethod(){
// leaving this empty
}
}
No es una forma realmente agradable de crear métodos de protocolo opcionales, pero le brinda la posibilidad de usar estructuras en devoluciones de llamada de protocolo.
Escribí un pequeño resumen aquí: https://www.avanderlee.com/swift-2-0/optional-protocol-methods/
Dado que hay algunas respuestas sobre cómo usar el modificador opcional y el atributo @objc para definir el protocolo de requisitos opcionales, daré una muestra sobre cómo usar las extensiones de protocolo para definir el protocolo opcional.
El siguiente código es 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*
Tenga en cuenta que los métodos de extensión de protocolo no pueden ser invocados por el código Objective-C, y lo peor es que el equipo Swift no lo solucionará. https://bugs.swift.org/browse/SR-492
Las otras respuestas aquí que implican marcar el protocolo como "@objc" no funcionan cuando se usan tipos específicos de 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"
Para declarar protocolos opcionales que funcionen bien con swift, declare las funciones como variables en lugar de funciones.
protocol Health {
var isInfoHealthy: (Info) -> (Bool)? { get set }
}
Y luego implemente el protocolo de la siguiente manera
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)?
}
Entonces puedes usar "?" para verificar si la función se ha implementado o no
func returnEntity() -> Health {
return Human()
}
var anEntity: Health = returnEntity()
var isHealthy = anEntity.isInfoHealthy(Info(height: 75, weight: 150))?
//"isHealthy" is true
Aquí hay un ejemplo concreto con el patrón de delegación.
Configure su protocolo:
@objc protocol MyProtocol:class
{
func requiredMethod()
optional func optionalMethod()
}
class MyClass: NSObject
{
weak var delegate:MyProtocol?
func callDelegate()
{
delegate?.requiredMethod()
delegate?.optionalMethod?()
}
}
Establezca el delegado en una clase e implemente el Protocolo. Ver que el método opcional no necesita ser implementado.
class AnotherClass: NSObject, MyProtocol
{
init()
{
super.init()
let myInstance = MyClass()
myInstance.delegate = self
}
func requiredMethod()
{
}
}
Una cosa importante es que el método opcional es opcional y necesita un "?" al llamar Mencione el segundo signo de interrogación.
delegate?.optionalMethod?()
En Swift 3.0
@objc protocol CounterDataSource {
@objc optional func increment(forCount count: Int) -> Int
@objc optional var fixedIncrement: Int { get }
}
Te ahorrará tiempo.
@objc
se necesita en todos los miembros ahora?
required
flag, pero con errores: required
solo se puede usar en declaraciones 'init'.
optional
palabra clave antes de cada método.@objc
, no solo el protocolo.
Para ilustrar la mecánica de la respuesta de Antoine:
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"
Creo que antes de preguntar cómo puede implementar un método de protocolo opcional, debería preguntarse por qué debería implementar uno.
Si pensamos en los protocolos rápidos como una interfaz en la programación orientada a objetos clásica, los métodos opcionales no tienen mucho sentido, y tal vez una mejor solución sería crear una implementación predeterminada o separar el protocolo en un conjunto de protocolos (tal vez con algunas relaciones de herencia entre ellos) para representar la posible combinación de métodos en el protocolo.
Para más información, consulte https://useyourloaf.com/blog/swift-optional-protocol-methods/ , que ofrece una excelente descripción general sobre este asunto.
Ligeramente fuera del tema de la pregunta original, pero se basa en la idea de Antoine y pensé que podría ayudar a alguien.
También puede hacer que las propiedades calculadas sean opcionales para estructuras con extensiones de protocolo.
Puede hacer que una propiedad en el protocolo sea opcional
protocol SomeProtocol {
var required: String { get }
var optional: String? { get }
}
Implemente la propiedad calculada ficticia en la extensión de protocolo
extension SomeProtocol {
var optional: String? { return nil }
}
Y ahora puede usar estructuras que tienen o no implementada la propiedad opcional
struct ConformsWithoutOptional {
let required: String
}
struct ConformsWithOptional {
let required: String
let optional: String?
}
También he escrito cómo hacer propiedades opcionales en los protocolos Swift en mi blog , que mantendré actualizado en caso de que las cosas cambien a través de las versiones de Swift 2.
Cómo crear métodos delegados opcionales y necesarios.
@objc protocol InterViewDelegate:class {
@objc optional func optfunc() // This is optional
func requiredfunc()// This is required
}
Aquí hay un ejemplo muy simple para clases rápidas SOLAMENTE, y no para estructuras o enumeraciones. Tenga en cuenta que el método de protocolo es opcional, tiene dos niveles de encadenamiento opcional en juego. Además, la clase que adopta el protocolo necesita el atributo @objc en su declaración.
@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!)
}
}
delegate?.indexDidChange?(index!)
:?
protocol CollectionOfDataDelegate{ func indexDidChange(index: Int) }
entonces lo llamaría sin el signo de interrogación: delegate?.indexDidChange(index!)
cuando establece un requisito opcional para un método en un protocolo, el Tipo que se ajuste a él NO podría implementar ese método , por lo que ?
se utiliza para verificar la implementación y, si no hay ninguna, el programa no se bloqueará. @Unheilig
weak var delegate : CollectionOfDataDelegate?
(¿asegurar una referencia débil?)
delegate?
uso a tu respuesta? Esa información realmente debería pertenecer a otros en el futuro. Quiero votar esto, pero esa información realmente debería estar en la respuesta.
si desea hacerlo de manera rápida, la mejor manera es proporcionar una implementación predeterminada particularmente si devuelve un tipo Swift como, por ejemplo, struct con tipos Swift
ejemplo:
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()
}
}
entonces puede implementar el protocolo sin definir cada función
Hay dos formas de crear un método opcional en un protocolo rápido.
1 - La primera opción es marcar su protocolo usando el atributo @objc. Si bien esto significa que solo puede ser adoptado por las clases, significa que marca métodos individuales como opcionales como este:
@objc protocol MyProtocol {
@objc optional func optionalMethod()
}
2 - Una forma más rápida: esta opción es mejor. Escriba implementaciones predeterminadas de los métodos opcionales que no hacen nada, como este.
protocol MyProtocol {
func optionalMethod()
func notOptionalMethod()
}
extension MyProtocol {
func optionalMethod() {
//this is a empty implementation to allow this method to be optional
}
}
Swift tiene una característica llamada extensión que nos permite proporcionar una implementación predeterminada para aquellos métodos que queremos que sean opcionales.
Una opción es almacenarlos como variables de función opcionales:
struct MyAwesomeStruct {
var myWonderfulFunction : Optional<(Int) -> Int> = nil
}
let squareCalculator =
MyAwesomeStruct(myWonderfulFunction: { input in return input * input })
let thisShouldBeFour = squareCalculator.myWonderfulFunction!(2)
Defina la función en el protocolo y cree una extensión para ese protocolo, luego cree una implementación vacía para la función que desea usar como opcional.
Para definir Optional
Protocol
rápidamente, debe usar la @objc
palabra clave antes de la Protocol
declaración y attribute
/ method
declaración dentro de ese protocolo. A continuación se muestra una muestra de la propiedad opcional de un protocolo.
@objc protocol Protocol {
@objc optional var name:String?
}
class MyClass: Protocol {
// No error
}
Poner @optional
delante de métodos o propiedades.
@optional
Ni siquiera es la palabra clave correcta. Es optional
, y debe declarar la clase y el protocolo con el @objc
atributo.