2014-10-07 236 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