2014-10-07 21 views
7

in Objective-C del codice sembrava è piaciuto e ha lavorato in modo impeccabile,Conversione NSData in numero intero a Swift

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

Come si può fare a Swift?

risposta

14

Ti piace questa:

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

Assolutamente perfetto! Grazie! – dhint4

+1

o 'sizeofValue (random)' – newacct

+0

In Swift3: sizeof (NSInteger) diventa MemoryLayout . Size e println diventano stampati. – parleer

5

Si potrebbe trovare questo metodo utile se si sta facendo un sacco:

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 
} 

La funzione prende come parametro la posizione iniziale nei dati di leggere il tipo numerico e restituisce un valore del tipo inferito da qualunque cosa lo si assegna.

Ad esempio:

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

legge un numero intero di 4 byte dalla posizione 10 nei dati.

Se si modifica UInt32 su UInt16, verranno letti due byte.

+0

si prega di elaborare un po 'di più su come usarlo e quali sono i parametri per passare ... grazie. –

6

Per Swift 3, si può fare questo (little endian, ma simili per grande):

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

È possibile modificare questo, aggiungere farmaci generici, ecc per adattarsi altri tipi primitivi (e variarlo a seconda il endianness dei byte di dati).

+0

Questa è davvero la cosa che mi infastidisce un po 'di Swift. Questo è estremamente complicato per qualcosa che è tecnicamente estremamente semplice. Mi chiedo se il compilatore ottimizza tutti i bs via –

0

dati per interger grazie @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

grazie a @rghome :) – YannickSteph

0

mio contributo con un rapido 3.1 estensione:

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

Basta chiamare .int per ottenere il vostro valore, proprio come questo:

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

In Swift 4:

Ci sono un paio di cose da considerare quando si estrae un valore intero da un flusso Data. Signedness e Endianess. Così ho trovato una funzione in un'estensione a Data che deduce Signedness dal tipo di intero che si desidera estrarre e passa Endianess e Index come parametri. I tipi di numeri interi che possono essere estratti sono tutti conformi al protocollo FixedWidthInteger.

app: Questa funzione non controlla se la gamma Index è all'interno dei limiti del buffer Data quindi potrebbe bloccarsi a seconda della dimensione del tipo l'estratto in relazione alla fine del buffer.

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

Esempio:

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) 

Risultati:

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

Osservare le chiamate di funzione per vedere come viene inferito il tipo da estrarre. Naturalmente Endianess non ha senso per Int8 o UInt8, ma la funzione funziona come previsto.

I valori possono essere espressi in seguito su Int se necessario.

+0

Ciao - Hai una soluzione molto più semplice per la semplice conversione dei dati da <02> a UInt8 2 o Int 2? – richc

+1

@richc: il modo più semplice per ottenere un 'UInt8' è semplicemente usare un indice se si conosce esattamente l'indice del byte desiderato:' data [indice] ' –