奇怪的 Swift 4 类型系统
Posted
技术标签:
【中文标题】奇怪的 Swift 4 类型系统【英文标题】:Weird Swift 4 type system 【发布时间】:2017-09-26 17:13:50 【问题描述】:有人能解释一下找出 Int 类型的最佳方法吗,自从 Swift 4 以来,我在使用 JSON 时遇到了很多麻烦
因为当我尝试将相同的 json 对象映射到核心数据实体和 PONSO 时,这种情况很常见
所以,
id: Int = json["id"] as? Int // works
id: Int32 = json["id"] as? Int32 // doesn't work
因此,我无法同时满足这两个要求。我能在 Swift 4 中避免这种绝对毫无意义的 int 情况吗?
【问题讨论】:
如果您有任何特定的 JSON 问题,请显示 JSON 以及您用于解析它的代码。 上面的代码没有展示任何与 JSON 相关的内容。[String: Any]
是“一个绝对可以用 Swift 表达的任何数据类型的 String 字典”。这通常被草率地用于 JSON,但是使用 NSJSONSerialization 解析 JSON 永远不应该生成您在此处给出的字典。以上没有什么是“毫无意义的”,它看起来完全符合规则,因此解释您要解决的问题可能会有所帮助。 JSON 没有 32 位或 64 位整数类型。
请注意,Swift 的 Int 与 ObjC 的 NSInteger 匹配,并且(就像在 ObjC 中一样)是 Swift 中几乎所有“类似整数”的东西的推荐类型。除非需要低级交互或确保 32 位平台上的非常大的整数,否则强烈建议不要使用特定的位宽。它们不是为在 Swift 中通用而设计的;它们专为您需要非常精确的尺寸并希望在您违反尺寸要求时收到警告而设计。
【参考方案1】:
之所以令人困惑,是因为as?
在 Swift 中具有两个完全正交的含义,具体取决于上下文。纯粹处理 Swift 类型时,as?
是一个动态转换,仅当类型实际上是 as?
运算符右侧的类型的实例时才返回非nil
:
import Foundation
let dict: [String : Any] = ["Foo" : 3 as Int]
print(dict["Foo"] as? Int)
print(dict["Foo"] as? Int32)
print(dict["Foo"] as? Int64)
这会为第一个日志返回 Optional(3)
,为其他两个返回 nil
,因为类型是 Int
,而不是 Int32
或 Int64
。
但是,当被投射的项目的类型是 Objective-C 类型时,那么 as?
不再是严格的动态投射,而是导致 bridging行为:
import Foundation
let dict: [String : Any] = ["Foo" : 3 as NSNumber]
print(dict["Foo"] as? Int)
print(dict["Foo"] as? Int32)
print(dict["Foo"] as? Int64)
这将为所有三个日志返回Optional(3)
,因为这不再是动态转换——事实上,NSNumber
实例不是我们尝试转换的三种类型中的任何一个的成员。相反,as?
使 Swift 将 Objective-C 类型 NSNumber
桥接 到适当的 Swift 类型(如果可以)。由于 Swift 具有将NSNumber
桥接到Int
、Int32
和Int64
(以及许多其他数字类型)的逻辑,因此我们得到所有三个日志的Optional(3)
。但是,如果您尝试转换为没有 NSNumber
桥接逻辑的 Decimal
之类的东西,您仍然会得到 nil
。
一个有趣的副作用是as?
不遵循传递属性:
let foo: Int = 3
print(foo as? NSNumber as? Int64) // Optional(3)
print(foo as? Int64) // nil
无论如何,如果您首先将您的值转换为 NSNumber
,那么您应该能够从那里转换为 Objective-C 桥支持的任何数字类型,这可能是引擎盖下发生的事情你的旧 Swift 3 代码。或者,如果您确实知道值应该是的类型,则可以使用其他整数类型的初始化器之一:
let dict: [String : Any] = ["Foo" : 3 as Int]
let foo = (dict["Foo"] as? Int).map Int32($0)
【讨论】:
以上是关于奇怪的 Swift 4 类型系统的主要内容,如果未能解决你的问题,请参考以下文章
ios swift将文本字段设置为数字键盘时会导致奇怪的错误
Swift入门——可选类型(Optionals)与断言(Assert)
Swift入门——可选类型(Optionals)与断言(Assert)