2014-10-07 99 views
7

NSData的转换为整数在Objective-C的代码看起来很喜欢这个和完美地工作,在斯威夫特

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

这怎么能在斯威夫特做?

回答

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 
+0

绝对完美!谢谢! – dhint4 2014-10-07 03:23:19

+1

或'sizeofValue(random)' – newacct 2014-10-07 19:24:11

+0

在Swift3中:sizeof(NSInteger)变为MemoryLayout .size并且println变为打印。 – parleer 2016-11-19 17:32:53

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,它将读取两个字节。

+0

请详细说明如何使用它以及通过哪些参数......谢谢。 – 2016-03-04 15:21:17

6

对于斯威夫特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) 
} 

您可以修改这一点,添加仿制药等,以适应其他的基本类型(它取决于变化数据字节的字节序)。

+0

这真的让我对Swift感到厌烦。对于技术上非常简单的东西,这是非常复杂的事情。我不知道编译器是否优化了所有的bs – 2017-08-02 09:31:50

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 
+0

谢谢@rghome :) – YannickSteph 2017-03-06 22:06:43

0

我与迅速延伸3.1的贡献:

extension NSData{ 
    var int : Int{ 
     var out: Int = 0 
     self.getBytes(&out, length: MemoryLayout<Int>.size) 
     return out 
    } 
} 

只需拨打.INT让你的价值,就像这样:

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

In Swift 4:

Data流中提取整数值时需要考虑几件事情。 签名Endianess。所以我想出了一个扩展功能Data,推断签名从你想要提取的整数类型,并通过EndianessIndex作为参数。可以提取的整数类型都符合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
number4 is 8191

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

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

+0

嗨 - 有没有更简单的解决方案,只是将数据<02>转换为UInt8 2或Int 2? – richc 2017-10-05 13:34:54

+1

@richc:获得'UInt8'的最简单方法是简单地使用下标,如果你确切知道你想要的字节的索引:'data [index]' – 2017-10-08 03:12:41