对于(U)Int8/16/32/64类型,是否可以将Swifts自动数值桥接复制到Foundation(NSNumber)?

dfr*_*fri 6 nsnumber swift swift2

  • 是否有可能复制雨燕数值桥接基金会:■ NSNumber引用类型,例如Int32,UInt32,Int64UInt64类型?具体来说,复制下面介绍的自动按配置桥接.

此类解决方案的示例用法:

let foo : Int64 = 42
let bar : NSNumber = foo
    /* Currently, as expected, error:
       cannot convert value of type 'Int64' to specified type 'NSNumber */
Run Code Online (Sandbox Code Playgroud)

背景

一些原生的Swift数(值)类型可以自动桥接到NSNumber(引用)类型:

迅数字结构类型的实例,例如Int,UInt, Float,Double,和Bool,不能由来表示 AnyObject类型,因为AnyObject仅代表一个类类型的实例.但是,Foundation启用桥接时,可以将Swift数值分配给常量和AnyObject类型的变量 作为类的桥接实例NSNumber.

...

雨燕自动填补某些本地号码类型,如IntFloat,对NSNumber.此桥接允许您NSNumber从以下类型之一创建 :

let n = 42
let m: NSNumber = n
Run Code Online (Sandbox Code Playgroud)

它还允许您将类型的值传递Int给例如期望的参数NSNumber....

以下所有类型都自动桥接到NSNumber:

- Int
- UInt
- Float
- Double
- Bool
Run Code Online (Sandbox Code Playgroud)

互操作性 - 使用Cocoa数据类型 - 数字.

那么为什么要尝试为IntXX/ UIntXXtypes 复制呢?

主要是:好奇心,最近看到一些问题引发的潜在问题,包括为什么Int价值类型似乎可以用AnyObject(参考)变量来表示的混淆,而例如Int64,不能; 这可以通过上面描述的桥接自然解释.选几个:

然而,上面提到的Q&A:没有提到从非桥接类型实际实现这种自动桥接到AnyObject(NSNumber)的可能性Int64,UInt16等等.这些线程中的答案非常集中(正确地)解释为什么AnyObject不能保存值类型,以及如何将IntXX/ UIntXX类型桥接为自动转换为前者的基础Foundation类型.

其次:对于在32位和64位体系结构中运行的应用程序,有一些狭隘的用例 - 使用Swift本机数字类型隐式转换为AnyObject,在某些上下文中 - 使用egInt32Int64type将优先于Int.一个(有点)这样的例子:

dfr*_*fri 11

是(可能):符合协议 _ObjectiveCBridgeable

(以下答案基于使用Swift 2.2和XCode 7.3.)

正如我在思考是否发布或只是跳过这个问题一样,我偶然发现了swift/stdlib/public/core/BridgeObjectiveC.swiftSwift源代码,特别是协议_ObjectiveCBridgeable.我之前在Swiftdoc.org上曾经简要地注意过这个协议,但是在后者的当前(空白)蓝图中,我从未考虑过它._ObjectiveCBridgeable但是,使用Swift源代码中的蓝图,我们可以迅速让一些自定义类型的本机符合它.

在继续之前,请注意这_ObjectiveCBridgeable是一个内部/隐藏协议(_UnderScorePreFixedProtocol),因此在即将推出的Swift版本中,基于它的解决方案可能会在没有警告的情况下中断.


启用Int64基础课程的桥接NSNumber

作为一个例子,扩展Int64以符合_ObjectiveCBridgeable,并随后测试这个非常简单的修复是否足以从隐式类型转换(桥接)Int64到基础类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
    }
}
Run Code Online (Sandbox Code Playgroud)

测试:

/* 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
Run Code Online (Sandbox Code Playgroud)

因此,一致性_ObjectiveCBridgeable确实足以实现自动的分配桥接到相应的基础课程; 在这种情况下,NSNumber(在Swift中__NSCFNumber).


启用Int8,UInt8,Int16,UInt16,Int32,UInt32,( Int64)和UInt64桥接NSNumber

使用下面的转换表Int64,_ObjectiveCBridgeable可以轻松修改to 的上述一致性以涵盖任何Swift原生整数类型NSNumber.

/* 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              */
Run Code Online (Sandbox Code Playgroud)