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

2024-06-19

Question

  • 是否可以将 Swifts 数值桥接复制到 Foundation:sNSNumber参考类型,例如Int32, UInt32, Int64 and 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(参考)类型:

Swift 数值结构类型的实例,例如Int, UInt, Float, Double, and Bool,不能用AnyObject类型,因为AnyObject只代表a的实例 类类型。然而,当桥接到Foundation已启用,斯威夫特 数值可以分配给常量和变量AnyObject输入为的桥接实例NSNumber class.

...

Swift 自动桥接某些本机数字类型,例如Int and Float, to NSNumber。通过此桥接,您可以创建一个NSNumber来自以下类型之一:

let n = 42
let m: NSNumber = n

它还允许您传递类型的值Int, 例如,到一个 论证期待NSNumber. ...

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

- Int
- UInt
- Float
- Double
- Bool

From 互操作性 - 使用 Cocoa 数据类型 - 数字 https://developer.apple.com/library/ios/documentation/Swift/Conceptual/BuildingCocoaApps/WorkingWithCocoaDataTypes.html.

那么为什么要尝试复制这个IntXX/UIntXX types?

主要是:最近看到一些问题引发了好奇心,这些问题的根本问题包括对为什么要这样做的困惑Int值类型看起来可以用AnyObject(参考)变量,而例如Int64, 不能;这自然可以通过上面介绍的桥接来解释。挑几个:

  • 为什么 Swift Array 与 AnyObject 兼容? https://stackoverflow.com/questions/35417438/why-is-a-swift-arrayint-compatible-with-anyobject/
  • 无法为“[UInt32]”类型的值添加下标 https://stackoverflow.com/questions/35668775/cannot-subscript-a-value-of-type-uint32/
  • 在 swift 中使用通用数组 https://stackoverflow.com/questions/30514268/using-generic-arrays-in-swift

然而,上面的问答都没有提到实际实现这种自动桥接的可能性AnyObject (NSNumber) 来自非桥接类型Int64, UInt16等等。这些线程中的答案更侧重于(正确地)解释原因AnyObject不能保存值类型,以及如何IntXX/UIntXX类型不会自动转换为前者的基础基础类型。

其次:对于在 32 位和 64 位架构上运行的应用程序,存在一些狭窄的用例 - 使用 Swift 本机数字类型隐式转换为AnyObject,在某些情况下,例如使用Int32 or Int64类型将优先于Int。一个(某种程度上)这样的例子:

  • 为什么这个随机函数代码在 iPhone 5 和 5S 上会崩溃? https://stackoverflow.com/questions/35462750/why-does-this-random-function-code-crash-on-an-iphone-5-and-5s

是(有可能):符合协议_ObjectiveCBridgeable

(以下答案基于使用斯威夫特2.2和 XCode 7.3。)

正当我思考是否要发布或干脆跳过这个问题时,我偶然发现swift/stdlib/public/core/BridgeObjectiveC.swift https://github.com/apple/swift/blob/master/stdlib/public/core/BridgeObjectiveC.swift在 Swift 源代码中,特别是协议_ObjectiveCBridgeable。我之前曾短暂注意到该协议Swiftdoc.org http://swiftdoc.org/v2.1/protocol/_ObjectiveCBridgeable/,但在后者目前的(空)蓝图形式中,我从未对其进行过太多思考。使用蓝图_ObjectiveCBridgeable然而,从 Swift 源代码中,我们可以迅速让一些自定义类型的本机符合它。

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


启用Int64衔接基础课程NSNumber

举个例子,扩展Int64符合_ObjectiveCBridgeable,然后测试这个非常简单的修复是否足以进行隐式类型转换(桥接)Int64到基础班NSNumber holds.

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:

/* 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确实足以启用自动分配桥接到相应的基础类;在这种情况下,NSNumber(在斯威夫特中,__NSCFNumber).


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

上述符合Int64 to _ObjectiveCBridgeable可以轻松修改以覆盖任何 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              */
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

是否可以将 Swifts 自动数值桥接复制到 (U)Int8/16/32/64 类型的 Foundation (NSNumber)? 的相关文章

随机推荐