是否可以为 (U)Int8/16/32/64 类型复制 Swifts 自动数值桥接到 Foundation (NSNumber)?
Posted
技术标签:
【中文标题】是否可以为 (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? 【发布时间】:2016-03-09 13:52:27 【问题描述】:问题
是否可以将 Swift 的数值桥接到 Foundation:sNSNumber
引用类型,例如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
(引用)类型:
Swift 数值结构类型的实例,例如
Int
、UInt
、Float
、Double
和Bool
,不能用AnyObject
类型,因为AnyObject
仅表示 a 的实例 类类型。然而,当桥接到Foundation
被启用时,Swift 数值可以分配给常量和变量AnyObject
类型为NSNumber
类的桥接实例。...
Swift 自动桥接某些本机数字类型,例如
Int
和Float
,到NSNumber
。这种桥接使您可以创建一个NSNumber
来自这些类型之一:let n = 42 let m: NSNumber = n
它还允许您将
Int
类型的值,例如,传递给 期望NSNumber
的参数。 ...以下所有类型都会自动桥接到 NSNumber:
- Int - UInt - Float - Double - Bool
来自Interoperability - Working with Cocoa Data Types - Numbers。
那么为什么要尝试为IntXX
/UIntXX
类型复制这个?
主要是:好奇心,最近看到一些问题引发了好奇心,这些问题涉及混淆为什么 Int
值类型似乎可以用 AnyObject
表示(参考)变量,而例如Int64
,不能;这自然可以通过上面介绍的桥接来解释。挑几个:
然而,上面的问答都没有提到从非桥接类型Int64
、UInt16
等实际实现这种自动桥接到AnyObject
(NSNumber
) 的可能性。这些线程中的答案更侧重于(正确地)解释为什么 AnyObject
不能保存值类型,以及如何不桥接 IntXX
/UIntXX
类型以自动转换为前者的基础 Foundation 类型。
其次:对于在 32 位和 64 位架构上运行的应用程序,有一些狭窄的用例——使用隐式转换为 @987654365 的 Swift 本机数字类型@,在某些情况下——在哪里使用例如Int32
或 Int64
类型将优先于 Int
。一个(有点)这样的例子:
【问题讨论】:
从 Swift 3 开始,固定大小的整数类型被桥接到 NSNumber (github.com/apple/swift-evolution/blob/master/proposals/…, github.com/apple/swift-evolution/blob/master/proposals/…)。 @MartinR 唉,Swift 的进步迅速吞噬了这些老生常谈的问答!感谢您的提示,下班后会尝试添加一些简短的注释。 【参考方案1】:是的(有可能):符合协议_ObjectiveCBridgeable
(以下答案基于使用 Swift 2.2 和 XCode 7.3。)
就在我考虑是发布还是直接跳过这个问题时,我偶然发现了 Swift 源代码中的swift/stdlib/public/core/BridgeObjectiveC.swift
,特别是协议_ObjectiveCBridgeable
。我之前在Swiftdoc.org 曾短暂地注意到该协议,但在后者的当前(空)蓝图形式中,我从未考虑过太多。但是,使用来自 Swift 源代码的 _ObjectiveCBridgeable
的蓝图,我们可以迅速让一些原生的自定义类型符合它。
在继续之前,请注意 _ObjectiveCBridgeable
是一个内部/隐藏协议 (_UnderScorePreFixedProtocol
),因此基于它的解决方案可能会在即将推出的 Swift 版本中中断而不会发出警告。
启用 Int64
桥接到 Foundation 类 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
测试:
/* 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
确实足以启用与相应Foundation 类的自动分配桥接;在这种情况下,NSNumber
(在 Swift 中,__NSCFNumber
)。
启用Int8
、UInt8
、Int16
、UInt16
、Int32
、UInt32
、(Int64
) 和UInt64
桥接至NSNumber
使用下面的NSNumber
转换表,可以轻松修改Int64
到_ObjectiveCBridgeable
的上述一致性以涵盖任何Swift 原生整数类型。
/* 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 */
【讨论】:
您的回答几乎非常全面。但是,正如 OP 所问:为什么要尝试为 IntXX/UIntXX 类型复制这个?我看不出比直接使用 NSNumber 构造函数(初始化器)有任何优势,它适用于每个 Swift 的“数字”类型。对我来说恰恰相反,我讨厌“免费”自动桥接。很容易出现错误,因为从 NSNumber (作为容器)使用哪个值完全取决于程序员的意愿。 (没有“类型安全”检查更多)。 @user3441734 请注意,我自己是 OP,我在这里回答了我自己的问题 :) 感谢您的反馈:尽管您的评论在讨论 对汽车的偏好方面很有价值。桥接(w.r.t. 直接使用NSNumber
构造函数),本问答主要涵盖汽车的技术方面。桥接,适合那些好奇的人以及喜欢使用后者的人。但是您的观点对于大多数 Swiftobj-C 互操作性普遍适用:我们远离“真正的”原生 Swift 代码的强类型安全性,如果不注意,我们可能会引入错误。
:-) 你的回答几乎很全面,OP一定很满意!
但是你不认为Apple不只是提供这些其他数字类型的自动桥接是一个错误吗?我有,而且我已经提交了那个错误。
@matt 我同意我们没有为其他数字类型免费获得这个很奇怪。至少,所有符合IntegerType
的类型(或没有)默认情况下都应该有这个桥接。幸好您已对此进行了标记。以上是关于是否可以为 (U)Int8/16/32/64 类型复制 Swifts 自动数值桥接到 Foundation (NSNumber)?的主要内容,如果未能解决你的问题,请参考以下文章
Typescript(真的)是不是遵循泛型中参数化类型(T、U、V、W)的命名约定?
如何将字符串类型从 API 响应转换为图像文件 - ����\u0000\u0010JFIF\u0000\u0001\u0001\u0000\u0000\u0001 -