swift swift2 nsnumber

¿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 tipos Int32 , UInt32 , Int64 y UInt64 ? 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 y Bool , no se pueden representar con el tipo AnyObject , porque AnyObject solo representa instancias de un tipo de clase. Sin embargo, cuando el puente a Foundation está habilitado, los valores numéricos de Swift se pueden asignar a constantes y variables de tipo AnyObject como instancias puenteadas de la clase NSNumber .

...

Swift NSNumber automáticamente ciertos tipos de números nativos, como Int y Float , a NSNumber . Este puente le permite crear un NSNumber 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 un NSNumber . ...

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:

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: