是否可以为 (U)Int8/16/32/64 类型复制 Swifts 自动数值桥接到 Foundation (NSNumber)?
Is it possible to replicate Swifts automatic numeric value bridging to Foundation (NSNumber) for (U)Int8/16/32/64 types?
问题
- 是否可以复制桥接到 Foundation:s
NSNumber
引用类型的 Swifts 数值,例如Int32
、UInt32
、Int64
和 UInt64
类型?具体来说,复制下面介绍的自动分配桥接。
此类解决方案的预期用法示例:
let foo : Int64 = 42
let bar : NSNumber = foo
/* Currently, as expected, error:
cannot convert value of type 'Int64' to specified type 'NSNumber */
背景
一些原生的Swift数字(值)类型可以自动桥接到NSNumber
(参考)类型:
Instances of the Swift numeric structure types, such as Int
, UInt
,
Float
, Double
, and Bool
, cannot be represented by the
AnyObject
type, because AnyObject
only represents instances of a
class type. However, when bridging to Foundation
is enabled, Swift
numeric values can be assigned to constants and variables of
AnyObject
type as bridged instances of the NSNumber
class.
...
Swift automatically bridges certain native number types, such as Int
and Float
, to NSNumber
. This bridging lets you create an
NSNumber
from one of these types:
let n = 42
let m: NSNumber = n
It also allows you to pass a value of type Int
, for example, to an
argument expecting an NSNumber
. ...
All of the following types are automatically bridged to NSNumber:
- Int
- UInt
- Float
- Double
- Bool
来自 Interoperability - Working with Cocoa Data Types - Numbers.
那么为什么要尝试为 IntXX
/UIntXX
类型复制这个?
主要是: 好奇心,最近看到一些问题引发了一些潜在问题,这些问题包括对 Int
值类型的混淆似乎可以用 AnyObject
(参考)变量表示,而例如Int64
, 不能;这自然可以通过上面提到的桥接来解释。挑几个:
- Using generic arrays in swift
None of Q&A:s above mentions, however, the possibility of actually implementing such automatic bridging to AnyObject
(NSNumber
) from the non-bridged types Int64
, UInt16
等等。这些线程中的答案(正确地)集中在解释为什么 AnyObject
不能保存值类型,以及 IntXX
/UIntXX
类型如何不桥接以自动转换为底层基础类型前者。
其次: 对于 32 位和 64 位架构的应用程序 运行,有一些狭窄的用途案例——使用 Swift 本机数字类型隐式转换为 AnyObject
,在某些情况下——使用例如Int32
或 Int64
类型优于 Int
。一个(有点)这样的例子:
是(可能):符合协议 _ObjectiveCBridgeable
(以下答案是基于使用Swift2.2和XCode7.3。)
正当我在考虑是 post 还是干脆跳过这个问题时,我偶然发现了 swift/stdlib/public/core/BridgeObjectiveC.swift
in the Swift source code, specifically the protocol _ObjectiveCBridgeable
. I've briefly noticed the protocol previously at Swiftdoc.org,但在后者当前的(空)蓝图形式中,我从来没有深思熟虑。然而,使用来自 Swift 源的 _ObjectiveCBridgeable
的蓝图,我们可以迅速让一些本地自定义类型符合它。
在继续之前,请注意 _ObjectiveCBridgeable
是一个 internal/hidden 协议 (_UnderScorePreFixedProtocol
),因此基于它的解决方案可能会在即将到来的 Swift 版本中毫无警告地中断。
启用 Int64
桥接到 Foundation class NSNumber
例如,扩展 Int64
以符合 _ObjectiveCBridgeable
,然后测试这个非常简单的修复是否足以实现从 Int64
到 Foundation 的隐式类型转换(桥接) class 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
}
}
测试:
/* 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
因此,符合 _ObjectiveCBridgeable
确实足以启用自动按分配桥接到相应的基金会 class;在这种情况下,NSNumber
(在 Swift、__NSCFNumber
中)。
启用Int8
、UInt8
、Int16
、UInt16
、Int32
、UInt32
、(Int64
),以及 UInt64
桥接到 NSNumber
上述 Int64
与 _ObjectiveCBridgeable
的一致性可以很容易地修改以涵盖任何 Swift-native 整数类型,使用 NSNumber
转换 table 下面。
/* 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 */
问题
- 是否可以复制桥接到 Foundation:s
NSNumber
引用类型的 Swifts 数值,例如Int32
、UInt32
、Int64
和UInt64
类型?具体来说,复制下面介绍的自动分配桥接。
此类解决方案的预期用法示例:
let foo : Int64 = 42
let bar : NSNumber = foo
/* Currently, as expected, error:
cannot convert value of type 'Int64' to specified type 'NSNumber */
背景
一些原生的Swift数字(值)类型可以自动桥接到NSNumber
(参考)类型:
Instances of the Swift numeric structure types, such as
Int
,UInt
,Float
,Double
, andBool
, cannot be represented by theAnyObject
type, becauseAnyObject
only represents instances of a class type. However, when bridging toFoundation
is enabled, Swift numeric values can be assigned to constants and variables ofAnyObject
type as bridged instances of theNSNumber
class....
Swift automatically bridges certain native number types, such as
Int
andFloat
, toNSNumber
. This bridging lets you create anNSNumber
from one of these types:let n = 42 let m: NSNumber = n
It also allows you to pass a value of type
Int
, for example, to an argument expecting anNSNumber
. ...All of the following types are automatically bridged to NSNumber:
- Int - UInt - Float - Double - Bool
来自 Interoperability - Working with Cocoa Data Types - Numbers.
那么为什么要尝试为 IntXX
/UIntXX
类型复制这个?
主要是: 好奇心,最近看到一些问题引发了一些潜在问题,这些问题包括对 Int
值类型的混淆似乎可以用 AnyObject
(参考)变量表示,而例如Int64
, 不能;这自然可以通过上面提到的桥接来解释。挑几个:
- Using generic arrays in swift
None of Q&A:s above mentions, however, the possibility of actually implementing such automatic bridging to AnyObject
(NSNumber
) from the non-bridged types Int64
, UInt16
等等。这些线程中的答案(正确地)集中在解释为什么 AnyObject
不能保存值类型,以及 IntXX
/UIntXX
类型如何不桥接以自动转换为底层基础类型前者。
其次: 对于 32 位和 64 位架构的应用程序 运行,有一些狭窄的用途案例——使用 Swift 本机数字类型隐式转换为 AnyObject
,在某些情况下——使用例如Int32
或 Int64
类型优于 Int
。一个(有点)这样的例子:
是(可能):符合协议 _ObjectiveCBridgeable
(以下答案是基于使用Swift2.2和XCode7.3。)
正当我在考虑是 post 还是干脆跳过这个问题时,我偶然发现了 swift/stdlib/public/core/BridgeObjectiveC.swift
in the Swift source code, specifically the protocol _ObjectiveCBridgeable
. I've briefly noticed the protocol previously at Swiftdoc.org,但在后者当前的(空)蓝图形式中,我从来没有深思熟虑。然而,使用来自 Swift 源的 _ObjectiveCBridgeable
的蓝图,我们可以迅速让一些本地自定义类型符合它。
在继续之前,请注意 _ObjectiveCBridgeable
是一个 internal/hidden 协议 (_UnderScorePreFixedProtocol
),因此基于它的解决方案可能会在即将到来的 Swift 版本中毫无警告地中断。
启用 Int64
桥接到 Foundation class NSNumber
例如,扩展 Int64
以符合 _ObjectiveCBridgeable
,然后测试这个非常简单的修复是否足以实现从 Int64
到 Foundation 的隐式类型转换(桥接) class 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
}
}
测试:
/* 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
因此,符合 _ObjectiveCBridgeable
确实足以启用自动按分配桥接到相应的基金会 class;在这种情况下,NSNumber
(在 Swift、__NSCFNumber
中)。
启用Int8
、UInt8
、Int16
、UInt16
、Int32
、UInt32
、(Int64
),以及 UInt64
桥接到 NSNumber
上述 Int64
与 _ObjectiveCBridgeable
的一致性可以很容易地修改以涵盖任何 Swift-native 整数类型,使用 NSNumber
转换 table 下面。
/* 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 */