在Swift中安全地从Int转换为Int8

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了在Swift中安全地从Int转换为Int8相关的知识,希望对你有一定的参考价值。

我通过api json响应(我将其转换为[String: Any]字典)接收一组整数。这些整数保证在10 ... -10(包括)范围内。在我的模型中,我想将它们存储为Int8

这就是我将我的json字典转换为它的模型对象的方法,但我想知道是否有一种更惯用的方法来确保json中的int实际上适合Int8

func move(with dict: JSONDictionary) -> Move? {
    if let rowOffset = dict[JSONKeys.rowOffsetKey] as? Int,
       let colOffset = dict[JSONKeys.colOffsetKey] as? Int {

      if let rowInt8 = Int8(exactly: rowOffset),
         let colInt8 = Int8(exactly: colOffset) {

        return Move(rowOffset: rowInt8, colOffset: colInt8)
      }
      else {
        print("Error: values out of range: (row: (rowOffset), col: (colOffset)")
      }
    } else {
      print("Error: Missing key, either: (JSONKeys.rowOffsetKey) or (JSONKeys.colOffsetKey)")
    }

    return nil
  }

请注意,无论传入的int值如何,执行以下操作始终会失败:

if let rowOffset = dict[JSONKeys.rowOffsetKey] as? Int8,
   let colOffset = dict[JSONKeys.colOffsetKey] as? Int8 {
...

这就是我将传入的json转换为字典的方式。有问题的json是深层嵌套的,包含几种不同的类型。

typealias JSONDictionary = [String: Any]
let jsonDict = try JSONSerialization.jsonObject(with: data) as? JSONDictionary
答案

以下是将Int(来自NSNumber)转换为Int8的一些选项:

只需使用Int8的初始化程序init(_: Int)进行转换

如果你的Int值保证适合Int8,那么用Int8(value)转换它们就可以了。

如果你得到一个不适合IntInt8,你的程序将崩溃:

let i = 300
let j = Int8(i)  // crash!

使用Int8的初始化程序init(truncatingIfNeeded: BinaryInteger)进行初始化

为了更加安全,您应该使用init(truncatingIfNeeded: BinaryInteger)初始化程序:

let i = 300
let j = Int8(truncatingIfNeeded: i)  // j = 44

这确实产生了可能不合需要的改变值,但它可以防止崩溃。

明确检查有效值的范围

作为另一种选择,您可以明确检查范围:

if (-10...10).contains(i) {
    j = Int8(i)
} else {
    // do something with the error case
}

检查的优点是您可以指定有效范围,而不是仅在范围超过适合Int8的值时检测错误。

使用Int8的初始化程序init(exactly: Int)进行初始化

您的代码目前正在使用这种安全初始化Int8值的方法。这很稳健,因为如果该值不适合nil,它将返回Int8。因此,它可以使用可选绑定进行检查,或者可以与nil合并运算符??结合使用,以提供默认值(如果您有适当的值):

// Determine Int8 value, use 0 if value would overflow an Int8
let j = Int8(exactly: i) ?? 0

NSNumber及以上直接与as Int8铸造Swift 3.0.1

正如@Hamish和@OOPer在评论中提到的,现在可以将NSNumber直接投射到Int8

let i: NSNumber = 300
let j = i as Int8  // j = 44

这与使用init(truncatingIfNeeded: BinaryInteger)具有相同的截断效果。

总之,您当前的代码是安全的,并且可能是您问题的最佳解决方案,除非您想要检测值何时超过当前所需的-10...10范围,在这种情况下,显式检查将是更好的选择。

以上是关于在Swift中安全地从Int转换为Int8的主要内容,如果未能解决你的问题,请参考以下文章

Swift 4 将字符串转换为 UnsafeMutablePointer<Int8>

swift3.0 无法将类型“[UnsafeMutablePointer<Int8>]”的值转换为预期的参数类型“UnsafeMutablePointer<Int8>?”

将 C 字符数组转换为字符串

iOS:将 UnsafeMutablePointer<Int8> 快速转换为字符串?

matlab中怎样将double型矩阵转换为int8型矩阵

C ++ 11 int8_t buggy输入/输出