2011-02-01 28 views
7

Ho un elemento NSData che contiene un gruppo di intarsi. Come faccio a portarli fuori e dentro un NSArray?Obj-C Come convertire NSData in una matrice di ints?

La struttura di memoria in NSData è a 32 bit int in ordine little-endian, uno subito dopo l'altro.

Spiacente per la domanda di base, ma ancora imparando il modo obj-c di fare le cose :)

risposta

13

È possibile utilizzare le funzioni definite in a che fare con endianness. A parte questa stranezza, si tratta solo di afferrare il buffer di byte e iterarlo su di esso.

// returns an NSArray containing NSNumbers from an NSData 
// the NSData contains a series of 32-bit little-endian ints 
NSArray *arrayFromData(NSData *data) { 
    void *bytes = [data bytes]; 
    NSMutableArray *ary = [NSMutableArray array]; 
    for (NSUInteger i = 0; i < [data length]; i += sizeof(int32_t)) { 
     int32_t elem = OSReadLittleInt32(bytes, i); 
     [ary addObject:[NSNumber numberWithInt:elem]]; 
    } 
    return ary; 
} 
+0

Ho usato questo codice nel mio progetto e funziona bene. – Justin808

0

Una possibile soluzione qui di seguito. Per tenere conto di endianness, cercare Core Endian Reference nel set di documenti XCode (probabilmente si utilizzerà EndianS32_LtoN (litte a 32 bit per endianness nativo)).

int mem[]= {0x01, 0x02, 0x03, 0x04, 0xff}; 


NSData * data = [NSData dataWithBytes:mem length:sizeof(mem)*sizeof(int)]; 
NSMutableArray * ar = [NSMutableArray arrayWithCapacity:10]; 

/* read ints out of the data and add them to the array, one at a time */ 
int idx=0; 
for(;idx<[data length]/sizeof(int);idx+=sizeof(int)) 
     [ar addObject:[NSNumber numberWithInt:*(int *)([data bytes] + idx)]]; 

NSLog(@"Array:%@", ar); 
+0

Intendi dire int32_t? Questo codice non è rotto su x64? –

+1

Penso che 'int' sia ancora lungo 4 byte su x86_64. È "lungo" che corrisponde alla dimensione della parola. O più specificamente, 'int' è dipendente dal compilatore, ma in gcc e clang su tutte le architetture supportate da Cocoa, saranno 4 byte. Comunque, 'int32_t' sarebbe più appropriato (e puoi vedere cosa ho usato nella mia risposta). –

+0

Ho scritto il codice su x86_64 - int è ancora lungo 4 byte. Ma hai entrambi ragione, int32_t è più appropriato. – diciu

2

Suona come ci sono modi più puliti di fare quello che stai cercando di fare, ma questo dovrebbe funzionare:

NSData *data = ...; // Initialized earlier 
int *values = [data bytes], cnt = [data length]/sizeof(int); 
for (int i = 0; i < cnt; ++i) 
    NSLog(@"%d\n", values[i]); 
1

Questa risposta è molto simile ad altri risposte di cui sopra, ma ho trovato istruttivo giocare con getto della NSData byte di nuovo ad un [] array int32_t. Questo codice funziona correttamente su un processore little-endian (x64 nel mio caso), ma sarebbe silentemente sbagliato su big-endian (PPC) perché la rappresentazione in byte sarebbe big-endian.

int32_t raw_data[] = {0,1,2,3,4,5,6,7,8,9,10}; 
printf("raw_data has %d elements\n", sizeof(raw_data)/sizeof(*raw_data)); 
NSData *data = [NSData dataWithBytes:(void*)raw_data length:sizeof(raw_data)]; 
printf("data has %d bytes\n", [data length]); 
int32_t *int_data_out = (int32_t*) [data bytes]; 
for (int i=0; i<[data length]/4; ++i) 
    printf("int %d = %d\n", i, int_data_out[i]); 
[data release]; 
Problemi correlati