variable strong operator generic extension swift enums type-conversion typecast-operator

strong - Operador de conversión en swift



swift syntax (1)

Descargo de responsabilidad / TL; DR! Esta respuesta se refiere a la pregunta técnica sobre si es posible implementar mecanismos de puente implícitos entre diferentes tipos de Swift. La respuesta es: para algunos casos, sí, pero solo en un sentido limitado y por medio de "hacks": ¡no use esto es código de producción!

Abuso del protocolo interno Swift: podemos implementar mecanismos implícitos para objetos Obj-C (por ejemplo, NSString , NSString ...)

Como MartinR escribe en su comentario, los métodos de conversión personalizados no están presentes para swift (nativo).

Para la discusión técnica podemos, sin embargo, (ab) usar el protocolo interno _ObjectiveCBridgeable para permitir la _ObjectiveCBridgeable de puentes implícitos desde su enumeración a los objetos Obj-C, en este caso, por ejemplo, NSString . Para obtener más información detallada sobre el tema del protocolo interno _ObjectiveCBridgeable , consulte

Antes de continuar, citaré un descargo de responsabilidad de mi respuesta en el hilo de arriba:

... tenga en cuenta que _ObjectiveCBridgeable es un protocolo interno / oculto ( _UnderScorePreFixedProtocol ), por lo que las soluciones basadas en él podrían romperse sin previo aviso en las próximas versiones de Swift.

Ejemplo n. ° 1: implementación de un puente implícito de tu enumeración a NSString

Primero permitamos agregar un inicializador failable a su enumeración, lo que permite la inicialización (intentada) por instancias String :

import Foundation enum MyEnum: Int { case Case1 = 0 case Case2 init?(string: String) { switch string { case "Case 1": self = .Case1 case "Case 2": self = .Case2 default: return nil } } }

A continuación, deje que MyEnum ajuste a _ObjectiveCBridgeable , como se describe con más detalle en el hilo vinculado a arriba.

extension MyEnum: _ObjectiveCBridgeable { typealias _ObjectiveCType = NSString static func _isBridgedToObjectiveC() -> Bool { return true } static func _getObjectiveCType() -> Any.Type { return _ObjectiveCType.self } func _bridgeToObjectiveC() -> _ObjectiveCType { return NSString(string: "Case /(self.rawValue+1)") } static func _forceBridgeFromObjectiveC(source: _ObjectiveCType, inout result: MyEnum?) { result = MyEnum(string: source as String) } static func _conditionallyBridgeFromObjectiveC(source: _ObjectiveCType, inout result: MyEnum?) -> Bool { self._forceBridgeFromObjectiveC(source, result: &result) return true } }

Con la conformidad anterior, ahora podemos hacer uso de un puente implícito desde instancias NSString a NSString

/* example usage */ var myCase: MyEnum = .Case1 var enumNSstr: NSString = myCase // MyEnum -> NSString, implicit print(enumNSstr) // Case 1 enumNSstr = "Case 2" // NSString -> MyEnum, by type conversion (castable) myCase = (enumNSstr as MyEnum) ?? .Case1 print(myCase) // Case 2

Ejemplo n. ° 2: implementar un puente implícito de tu enumeración a un tipo nativo Swift personalizado

Incluso podemos abusar aún más del protocolo _ObjectiveCBridgeable , utilizando sus mecanismos (back-end profundos) para implementar puentes implícitos entre dos tipos Swift nativos, con la limitación de que el tipo puenteado debe ser un tipo de referencia (específicamente: las instancias del tipo deben ser representables por AnyObject , de ahí la limitación del tipo de referencia).

Deje que MyEnum sea ​​como se definió anteriormente, pero, además, defina un tipo de referencia (clase) Foo , y MyEnum a _ObjectiveCBridgeable con el puenteado para escribir , _ObjectiveCType establecido en Foo .

class Foo { var bar: String init(bar: String) { self.bar = bar } } extension MyEnum: _ObjectiveCBridgeable { typealias _ObjectiveCType = Foo static func _isBridgedToObjectiveC() -> Bool { return true } static func _getObjectiveCType() -> Any.Type { return _ObjectiveCType.self } func _bridgeToObjectiveC() -> _ObjectiveCType { return Foo(bar: "Case /(self.rawValue+1)") } static func _forceBridgeFromObjectiveC(source: _ObjectiveCType, inout result: MyEnum?) { result = MyEnum(string: source.bar) } static func _conditionallyBridgeFromObjectiveC(source: _ObjectiveCType, inout result: MyEnum?) -> Bool { self._forceBridgeFromObjectiveC(source, result: &result) return true } }

Ahora podemos hacer uso de un puente implícito desde instancias MyEnum a Foo

/* example usage */ var myCase: MyEnum = .Case1 var myFoo: Foo = myCase // MyEnum -> Foo, implicit print(myFoo.bar) // Case 1 myFoo.bar = "Case 2" // Foo -> MyEnum, by type conversion (castable) myCase = (myFoo as? MyEnum) ?? .Case1 print(myCase) // Case 2

Finalmente, tenga en cuenta que puede, para cualquier tipo dado (digamos, MyEnum ), naturalmente, solo implementar el puente implícito a un único otro tipo (de referencia); ya que solo puede ajustarse a _ObjectiveCType una vez (para un tipo único para las typealias _ObjectiveCType ), de lo contrario producirá un error de tiempo de compilación para la conformidad del protocolo redundante.

Lo anterior se prueba para Swift 2.2.

¿Es posible escribir un operador de conversión personalizado (casting) de forma swift ? Especialmente estoy buscando la conversión de enums, por ejemplo:

enum MyEnum : Int { case Case1 = 0 case Case2 func __conversion() -> String { // doesn''t work since Swift 1.0 switch self { case Case1: return "Case 1" case Case2: return "Case 2" } } } let enumStr: String = MyEnum.Case1

Por supuesto, puedo convertir a String con un método explícito, pero me gustaría tener un mecanismo implícito.