2014-10-07 14 views
7

In Objective-C den Code Converting sah dies gern und funktionierte einwandfrei,NSData zu Integer in Swift

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

Wie dies in Swift kann getan werden?

Antwort

14

So:

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

Absolut perfekt! Vielen Dank! – dhint4

+1

oder 'sizeofValue (random)' – newacct

+0

In Swift3: sizeof (NSInteger) wird MemoryLayout .size und println wird gedruckt. – parleer

5

Sie könnten diese Methode hilfreich sein, wenn Sie es eine Menge tun:

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 
} 

Die Funktion nimmt als Parameter die Startposition in den Daten der lesen numerischer Typ und gibt einen Wert des a-Typs zurück, der von dem abgeleitet wurde, dem Sie ihn zuweisen.

Zum Beispiel:

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

liest eine 4-Byte-Ganzzahl von der Position 10 in den Daten.

Wenn Sie UInt32 zu UInt16 ändern, liest es zwei Bytes.

+0

bitte erläutern Sie, wie Sie es verwenden können und welche Parameter zu übergeben sind ... danke. –

6

Für Swift 3, können Sie diese (Little-Endian, aber ähnlich für groß) tun:

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) 
} 

Sie diese ändern können, fügen Generika usw. andere primitive Typen zu passen (und variieren sie je nach die Endianz der Datenbytes).

+0

Das ist wirklich das, was mich ein bisschen an Swift ärgert. Dies ist extrem komplizierte Dinge für etwas, das technisch extrem einfach ist. Ich frage mich, ob der Compiler optimiert alle BS weg –

0

Daten interger Dank @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

Danke @RGHOME :) – YannickSteph

0

Mein Beitrag mit einer schnellen 3.1-Erweiterung:

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

Nur .int rufen Sie Ihren Wert zu erhalten, so wie diese:

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

In Swift 4:

Beim Extrahieren eines ganzzahligen Werts aus einem Data-Stream sind einige Punkte zu beachten. Signigness und Endianess. So kam ich mit einer Funktion in einer Erweiterung zu , die Signedness von dem Typ der Ganzzahl, die Sie extrahieren möchten, und übergibt Endianess und Index als Parameter. Die Typen von Ganzzahlen, die extrahiert werden können, entsprechen dem FixedWidthInteger Protokoll.

Erinnerung: Diese Funktion wird nicht überprüfen, ob die Index Bereich innerhalb der Grenzen des Data Puffers ist, so dass es abhängig von der Größe des Typs abstürzen kann in Bezug auf das Ende des Puffers extrahiert wird.

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 
     } 
    } 
} 

Beispiel:

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) 

Ergebnisse:

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

Beobachten Sie die Funktionsaufrufe, um zu sehen, wie der zu extrahierende Typ abgeleitet wird. Natürlich Endianess macht keinen Sinn für Int8 oder UInt8, aber die Funktion funktioniert wie erwartet.

Werte können später bei Bedarf in Int umgewandelt werden.

+0

Hallo - Haben Sie eine viel einfachere Lösung für nur Konvertierung von Daten <02> zu UInt8 2 oder Int 2? – richc

+1

@richc: Der einfachste Weg, ein 'UInt8' zu erhalten, besteht darin, einfach einen Index zu verwenden, wenn Sie genau den Index des gewünschten Bytes kennen:' data [index] ' –