在Swift中将NSData转换为Integer

时间:2014-10-07 02:30:23

标签: swift integer nsdata

在Objective-C中,代码看起来很喜欢这个并且完美无缺,

NSInteger random = arc4random_uniform(99) + 1 
NSData *data = [NSData dataWithBytes:& random length: sizeof(random)];
int value = *(int*)([data bytes]);

如何在Swift中完成?

7 个答案:

答案 0 :(得分:14)

像这样:

var src: NSInteger = 2525
var out: NSInteger = 0

let data = NSData(bytes: &src, length: sizeof(NSInteger))
data.getBytes(&out, length: sizeof(NSInteger))
println(out) // ==> 2525

答案 1 :(得分:8)

在Swift 4中:

Data流中提取整数值时需要考虑几件事。 签名 Endianess 。所以我在Data的扩展中提出了一个函数,它根据要提取的整数类型推断 Signedness 并传递 Endianess 和{{1}作为参数。可以提取的整数类型都符合Index协议。

提醒:此函数不会检查FixedWidthInteger范围是否在Index缓冲区的范围内,因此可能会崩溃,具体取决于所提取类型的大小与缓冲区的结尾有关。

Data

示例:

extension Data {
    enum Endianness {
        case BigEndian
        case LittleEndian
    }
    func scanValue<T: FixedWidthInteger>(at index: Data.Index, endianess: Endianness) -> T {
        let number: T = self.subdata(in: index..<index + MemoryLayout<T>.size).withUnsafeBytes({ $0.pointee })
        switch endianess {
        case .BigEndian:
            return number.bigEndian
        case .LittleEndian:
            return number.littleEndian
        }
    }
}

<强>结果:

let data = Data(bytes: [0xFF,0x1F,0x1F,0xFF]) let number1 = data.scanValue(at: 0, endianess: .LittleEndian) as UInt16 let number2 = data.scanValue(at: 0, endianess: .BigEndian) as UInt16 let number3: Int16 = data.scanValue(at: 2, endianess: .LittleEndian) let number4: Int16 = data.scanValue(at: 2, endianess: .BigEndian)
number1 is 8191
number2 is 65311
number3 is -225

观察函数调用以查看如何推断要提取的类型。当然 Endianess number4 is 8191Int8没有意义,但该函数按预期工作。

如果需要,稍后可以将值转换为UInt8

答案 2 :(得分:6)

对于Swift 3,你可以这样做(小端,但类似于大):

func getInt(fromData data: Data, start: Int) -> Int32 {
  let intBits = data.withUnsafeBytes({(bytePointer: UnsafePointer<UInt8>) -> Int32 in
    bytePointer.advanced(by: start).withMemoryRebound(to: Int32.self, capacity: 4) { pointer in
      return pointer.pointee
    }
  })
  return Int32(littleEndian: intBits)
}

你可以修改它,添加泛型等以适应其他原始类型(并根据数据字节的字节顺序改变它)。

答案 3 :(得分:5)

如果你这么做的话,你会发现这个方法很有用:

func readInteger<T : IntegerType>(data : NSData, start : Int) -> T {
    var d : T = 0
    data.getBytes(&d, range: NSRange(location: start, length: sizeof(T)))
    return d
}

该函数将数据中的起始位置作为参数读取数字类型,并返回从您分配给它的任何内容推断出的类型的值。

例如:

let i : UInt32 = readInteger(data, 10);

从数据中的位置10读取一个4字节的整数。

如果您将UInt32更改为UInt16,则会读取两个字节。

答案 4 :(得分:0)

数据感谢@rghome

// MARK: - Extensions Data

extension Data {

    /// To interger Data by range
    ///
    /// - Parameters:
    ///   - data:       Data
    ///   - startRange: StartRange
    ///   - endRange:   EndRange
    /// - Returns:      Integer Typed
    func toInterger<T : Integer>(withData data: NSData, withStartRange startRange: Int, withSizeRange endRange: Int) -> T {
        var d : T = 0
        (self as NSData).getBytes(&d, range: NSRange(location: startRange, length: endRange))
        return d
    }
}

101010
let value:Int = Data().toInterger(withStartRange: 0, withEndRange: 2)
get 10
get 2 Int

答案 5 :(得分:0)

我对快速3.1扩展的贡献:

let value = 50
let data = NSData(bytes: &value, length: 4)
print(data.int)

只需调用.int即可获得您的价值,就像这样:

wp_postmeta

答案 6 :(得分:0)

您可以扩展数据协议,创建通用方法,从内存数据存储器返回字节并进行强制转换或根据需要显式设置结果类型:

extension Data {
    func object<T>() -> T {
        precondition(MemoryLayout<T>.size == count)
        return withUnsafeBytes{ $0.pointee }
    }
}

let data = Data([0xFF, 0x1F])   // 2 bytes

let uint16: UInt16 = data.object()      // 8191  littleEndian
let number1 = uint16.littleEndian       // 8191
let number2 = uint16.bigEndian          // 65311

let int16: Int16 = data.object()        // 8191   littleEndian
let number3 = int16.littleEndian        // 8191
let number4 = int16.bigEndian           // -225

print(number1) // 8191
print(number2) // 65311
print(number3) // 8191
print(number4) // -225

使用Int

进行测试
let random = Int.random(in: 1...100)    // 15 UInt32
let data = random.data                  // 8 bytes  [15, 0, 0, 0, 0, 0, 0, 0]

使用UInt32

进行测试
let random = UInt32.random(in: 1...100)  // 90 UInt32
let data = random.data                   // 4 bytes  [90, 0, 0, 0]

使用Double进行测试

let random = Double.random(in: 0...1)  // 0.2463145485351322 Double
let data = random.data                 // 8 bytes  [12, 99, 62, 49, 60, 135, 207, 63]

如果要提取子数据,只需将数据下标即可:

let data = Data([0xFF, 0x1F, 0x1F, 0xFF])      // 4 bytes
let startIndex = 2

let uint16: UInt16 = data[startIndex..<startIndex.advanced(by: MemoryLayout<UInt16>.size)].object()       //  65311 littleEndian
let number1 = uint16.littleEndian              // 65311
let number2 = uint16.bigEndian                 // 8191

let int16: Int16 = data[startIndex..<startIndex.advanced(by: MemoryLayout<Int16>.size)].object()       // -225   littleEndian
let number3 = int16.littleEndian               // -225
let number4 = int16.bigEndian                  // 8191

number1 // 65311
number2 // 8191
number3 // -225
number4 // 8191