¿Es posible replicar el puente de valor numérico automático de Swifts a Foundation(NSNumber) para los tipos(U) Int8/16/32/64?
swift2 (1)
Sí (es posible): de conformidad con el protocolo
_ObjectiveCBridgeable
(La siguiente respuesta se basa en el uso de Swift 2.2 y XCode 7.3.)
Justo cuando estaba pensando si publicar o simplemente omitir esta pregunta, me topé con
swift/stdlib/public/core/BridgeObjectiveC.swift
en el código fuente de Swift, específicamente el protocolo
_ObjectiveCBridgeable
.
He notado brevemente el protocolo anteriormente en
Swiftdoc.org
, pero en su forma de plano actual (vacía) en este último, nunca he pensado mucho en ello.
Sin embargo, utilizando los planos para
_ObjectiveCBridgeable
de la fuente Swift podemos dejar que algunos nativos de tipo personalizado se ajusten a él.
Antes de continuar, tenga en cuenta que
_ObjectiveCBridgeable
es un protocolo interno / oculto (
_UnderScorePreFixedProtocol
), por lo que las soluciones basadas en él pueden romperse sin previo aviso en las próximas versiones de Swift.
Habilitación del puente
Int64
a la clase Foundation
NSNumber
Como ejemplo, extienda
Int64
para cumplir con
_ObjectiveCBridgeable
, y luego pruebe si esta solución bastante simple es suficiente para la conversión de tipo implícito (puente) de
Int64
a la clase
NSNumber
.
import Foundation
extension Int64: _ObjectiveCBridgeable {
public typealias _ObjectiveCType = NSNumber
public static func _isBridgedToObjectiveC() -> Bool {
return true
}
public static func _getObjectiveCType() -> Any.Type {
return _ObjectiveCType.self
}
public func _bridgeToObjectiveC() -> _ObjectiveCType {
return NSNumber(longLong: self)
}
public static func _forceBridgeFromObjectiveC(source: _ObjectiveCType, inout result: Int64?) {
result = source.longLongValue
}
public static func _conditionallyBridgeFromObjectiveC(source: _ObjectiveCType, inout result: Int64?) -> Bool {
self._forceBridgeFromObjectiveC(source, result: &result)
return true
}
}
Prueba:
/* Test case: scalar */
let fooInt: Int = 42
let fooInt64: Int64 = 42
var fooAnyObj : AnyObject
fooAnyObj = fooInt // OK, natively
fooAnyObj = fooInt64 // OK! _ObjectiveCBridgeable conformance successful
/* Test case: array */
let fooIntArr: [Int] = [42, 23]
let fooInt64Arr: [Int64] = [42, 23]
var fooAnyObjArr : [AnyObject]
fooAnyObjArr = fooIntArr // OK, natively
fooAnyObjArr = fooInt64Arr // OK! _ObjectiveCBridgeable conformance successful
Por lo tanto, la conformidad con
_ObjectiveCBridgeable
es suficiente para permitir el puente automático de asignación secundaria a la clase Foundation correspondiente;
en este caso,
NSNumber
(en Swift,
__NSCFNumber
).
Habilitar
Int8
,
UInt8
,
Int16
,
UInt16
,
Int32
,
UInt32
, (
Int64
) y
UInt64
puente a
NSNumber
La conformidad anterior de
Int64
a
_ObjectiveCBridgeable
se puede modificar fácilmente para cubrir cualquiera de los tipos enteros nativos de Swift, utilizando la tabla de conversión
NSNumber
continuación.
/* NSNumber initializer: NSNumber native Swift type property
-------------------------------- -----------------------------------
init(char: <Int8>) .charValue
init(unsignedChar: <UInt8>) .unsignedCharValue
init(short: <Int16>) .shortValue
init(unsignedShort: <UInt16>) .unsignedShortValue
init(int: <Int32>) .intValue
init(unsignedInt: <UInt32>) .unsignedIntValue
init(longLong: <Int64>) .longLongValue
init(unsignedLongLong: <UInt64>) .unsignedLongLongValue */
Pregunta
-
¿Es posible replicar el puente numérico de valores Swifts en el tipo de referencia
NSNumber
Foundation: s, por ejemplo, para los tiposInt32
,UInt32
,Int64
yUInt64
? Específicamente, replicando el puente de asignación automática cubierto por debajo.
Ejemplo de uso previsto de dicha solución:
let foo : Int64 = 42
let bar : NSNumber = foo
/* Currently, as expected, error:
cannot convert value of type ''Int64'' to specified type ''NSNumber */
Antecedentes
Algunos de los tipos nativos de número (valor) de Swift se pueden
NSNumber
automáticamente al tipo
NSNumber
(referencia):
Las instancias de los tipos de estructura numérica Swift, como
Int
,UInt
,Float
,Double
yBool
, no se pueden representar con el tipoAnyObject
, porqueAnyObject
solo representa instancias de un tipo de clase. Sin embargo, cuando el puente aFoundation
está habilitado, los valores numéricos de Swift se pueden asignar a constantes y variables de tipoAnyObject
como instancias puenteadas de la claseNSNumber
....
Swift
NSNumber
automáticamente ciertos tipos de números nativos, comoInt
yFloat
, aNSNumber
. Este puente le permite crear unNSNumber
partir de uno de estos tipos:
let n = 42 let m: NSNumber = n
También le permite pasar un valor de tipo
Int
, por ejemplo, a un argumento que espera unNSNumber
. ...Todos los siguientes tipos se conectan automáticamente a NSNumber:
- Int - UInt - Float - Double - Bool
De la interoperabilidad - Trabajar con tipos de datos de cacao - Números .
Entonces, ¿por qué intentar replicar esto para los tipos
IntXX
/
UIntXX
?
Principalmente: La
curiosidad, provocada al ver algunas preguntas recientemente con problemas subyacentes que cubren la confusión sobre por qué un tipo de valor
Int
aparentemente puede ser representado por una
AnyObject
(referencia), mientras que, por ejemplo,
Int64
, no puede;
que se explica naturalmente por el puente cubierto anteriormente.
Para elegir algunos:
- ¿Por qué un Swift Array <Int> es compatible con AnyObject?
- No se puede subíndice un valor de tipo ''[UInt32]''
- Usar matrices genéricas en swift
Ninguna de las preguntas y respuestas anteriores mencionan, sin embargo, la posibilidad de implementar tal puente automático a
AnyObject
(
NSNumber
) desde los tipos no puenteados
Int64
,
UInt16
, etc.
Las respuestas en estos subprocesos se centran (correctamente) en explicar por qué
AnyObject
no puede contener tipos de valores y cómo los tipos
IntXX
/
UIntXX
no se
UIntXX
para la conversión automática a los tipos de Foundation subyacentes del primero.
En segundo lugar:
para las aplicaciones que se ejecutan en arquitecturas de 32 bits y de 64 bits, existen algunos casos de uso estrechos, que usan tipos de números nativos Swift convertidos implícitamente a
AnyObject
, en algún contexto, donde se preferiría usar, por ejemplo, el tipo
Int32
o
Int64
sobre
Int
.
Un ejemplo (algo) de este tipo: