dhi*_*nt4 7 integer nsdata swift
在Objective-C中,代码看起来很喜欢这个并且工作得很完美,
NSInteger random = arc4random_uniform(99) + 1
NSData *data = [NSData dataWithBytes:& random length: sizeof(random)];
int value = *(int*)([data bytes]);
Run Code Online (Sandbox Code Playgroud)
怎么能在Swift中完成?
fin*_*all 15
像这样:
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
Run Code Online (Sandbox Code Playgroud)
从Data流中提取整数值时,需要考虑几件事情.符号性和字节序.所以我在扩展中提出了一个函数,它从你想要提取的整数类型中Data推断出Signness,并传递Endianess和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
}
}
}
Run Code Online (Sandbox Code Playgroud)
例:
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)
Run Code Online (Sandbox Code Playgroud)
结果:
number1 is 8191
number2 is 65311
number3 is -225
number4 is 8191
观察函数调用以查看如何推断要提取的类型.当然字节序没有意义的Int8或UInt8,但功能正常工作.
Int如果需要,稍后可以转换为值.
对于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)
}
Run Code Online (Sandbox Code Playgroud)
您可以修改它,添加泛型等以适应其他基本类型(并根据数据字节的字节顺序来改变它).
您可以根据需要扩展数据类型、创建泛型方法、获取字节并对其进行转换或显式设置结果类型:
extension Data {
func object<T>(at index: Index = 0) -> T {
subdata(in: index..<self.index(index, offsetBy: MemoryLayout<T>.size))
.withUnsafeBytes { $0.load(as: T.self) }
}
}
Run Code Online (Sandbox Code Playgroud)
extension Numeric {
var data: Data {
var source = self
return Data(bytes: &source, count: MemoryLayout<Self>.size)
}
}
Run Code Online (Sandbox Code Playgroud)
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 = data.object() as Int16 // 8191 littleEndian
let number3 = int16.littleEndian // 8191
let number4 = int16.bigEndian // -225
print(number1) // 8191
print(number2) // 65311
print(number3) // 8191
print(number4) // -225
Run Code Online (Sandbox Code Playgroud)
测试 Int
let random = Int.random(in: 1...100) // 15 UInt32
let data = random.data // 8 bytes [15, 0, 0, 0, 0, 0, 0, 0]
Run Code Online (Sandbox Code Playgroud)
测试 UInt32
let random = UInt32.random(in: 1...100) // 90 UInt32
let data = random.data // 4 bytes [90, 0, 0, 0]
Run Code Online (Sandbox Code Playgroud)
用双重测试
let random = Double.random(in: 0...1) // 0.2463145485351322 Double
let data = random.data // 8 bytes [12, 99, 62, 49, 60, 135, 207, 63]
Run Code Online (Sandbox Code Playgroud)
如果要提取子数据:
let data = Data([0xFF, 0x1F, 0x1F, 0xFF]) // 4 bytes
let uint16: UInt16 = data.object(at: 2) // 65311 littleEndian
let number1 = uint16.littleEndian // 65311
let number2 = uint16.bigEndian // 8191
let int16: Int16 = data.object(at: 2) // -225 littleEndian
let number3 = int16.littleEndian // -225
let number4 = int16.bigEndian // 8191
number1 // 65311
number2 // 8191
number3 // -225
number4 // 8191
Run Code Online (Sandbox Code Playgroud)
如果您经常这样做,您可能会发现此方法很有用:
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
}
Run Code Online (Sandbox Code Playgroud)
该函数将数据中的起始位置作为参数读取数字类型,并返回从您分配给它的任何内容推断出的类型的值.
例如:
let i : UInt32 = readInteger(data, 10);
Run Code Online (Sandbox Code Playgroud)
从数据中的位置10读取4字节整数.
如果更改UInt32为UInt16它将读取两个字节.
| 归档时间: |
|
| 查看次数: |
11470 次 |
| 最近记录: |