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.