2015-08-08 21 views
9

Ho un oggetto NSData. Devo convertire i suoi byte in una stringa e inviarli come JSON. description restituisce esadecimale ed è inaffidabile (secondo vari poster SO). Così sto guardando il codice come questo:Converti l'array di byte NSData in stringa?

NSUInteger len = [imageData length]; 
Byte *byteData = (Byte*)malloc(len); 
[imageData getBytes:&byteData length:len]; 

Come faccio allora mando byteData come JSON? Voglio inviare i byte non elaborati.

CODICE:

NSString *jsonBase64 = [imageData base64EncodedString]; 
NSLog(@"BASE 64 FINGERPRINT: %@", jsonBase64); 
NSData *b64 = [NSData dataFromBase64String:jsonBase64]; 
NSLog(@"Equal: %d", [imageData isEqualToData:b64]); 
NSLog(@"b64: %@", b64); 
NSLog(@"original: %@", imageData); 
NSString *decoded = [[NSString alloc] initWithData:b64 encoding:NSUTF8StringEncoding]; 
NSLog(@"decoded: %@", decoded); 

ottengo valori per tutto tranne che per l'ultima riga - decoded. Quale potrebbe indicarmi che i byte non formattati non sono formattati in NSUTF8encoding?

+1

è 'imageData' l'oggetto NSData ed è rappresentabile dati come stringa JSON? – vadian

+1

In che formato vuoi inserire i byte? Codici esadecimali? Stringa codificata Base-64? Che cosa? – rmaddy

+1

Una stringa per JSON, sì. Per il titolo. – quantumpotato

risposta

6

Hai provato a usare qualcosa di simile:

@implementation NSData (Base64) 
- (NSString *)base64EncodedString 
{ 
    return [self base64EncodedStringWithWrapWidth:0]; 
} 

Questo trasformerà il vostro NSData in una stringa base64, e dall'altro lato si solo bisogno di decodificarlo.

EDIT: @Lucas detto che si può fare qualcosa di simile:

NSString *myString = [[NSString alloc] initWithData:myData encoding:NSUTF8StringEncoding]; 

, ma ho avuto qualche problema con questo metodo a causa di alcuni caratteri speciali, e per questo ho iniziato ad usare le stringhe base64 per la comunicazione.

Edit3: Trys questo metodo base64EncodedString

@implementation NSData (Base64) 

    - (NSString *)base64EncodedString 
    { 
     return [self base64EncodedStringWithWrapWidth:0]; 
    } 

    //Helper Method 
    - (NSString *)base64EncodedStringWithWrapWidth:(NSUInteger)wrapWidth 
    { 
     //ensure wrapWidth is a multiple of 4 
     wrapWidth = (wrapWidth/4) * 4; 

     const char lookup[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz/"; 

     long long inputLength = [self length]; 
     const unsigned char *inputBytes = [self bytes]; 

     long long maxOutputLength = (inputLength/3 + 1) * 4; 
     maxOutputLength += wrapWidth? (maxOutputLength/wrapWidth) * 2: 0; 
     unsigned char *outputBytes = (unsigned char *)malloc((NSUInteger)maxOutputLength); 

     long long i; 
     long long outputLength = 0; 
     for (i = 0; i < inputLength - 2; i += 3) 
     { 
      outputBytes[outputLength++] = lookup[(inputBytes[i] & 0xFC) >> 2]; 
      outputBytes[outputLength++] = lookup[((inputBytes[i] & 0x03) << 4) | ((inputBytes[i + 1] & 0xF0) >> 4)]; 
      outputBytes[outputLength++] = lookup[((inputBytes[i + 1] & 0x0F) << 2) | ((inputBytes[i + 2] & 0xC0) >> 6)]; 
      outputBytes[outputLength++] = lookup[inputBytes[i + 2] & 0x3F]; 

      //add line break 
      if (wrapWidth && (outputLength + 2) % (wrapWidth + 2) == 0) 
      { 
       outputBytes[outputLength++] = '\r'; 
       outputBytes[outputLength++] = '\n'; 
      } 
     } 

     //handle left-over data 
     if (i == inputLength - 2) 
     { 
      // = terminator 
      outputBytes[outputLength++] = lookup[(inputBytes[i] & 0xFC) >> 2]; 
      outputBytes[outputLength++] = lookup[((inputBytes[i] & 0x03) << 4) | ((inputBytes[i + 1] & 0xF0) >> 4)]; 
      outputBytes[outputLength++] = lookup[(inputBytes[i + 1] & 0x0F) << 2]; 
      outputBytes[outputLength++] = '='; 
     } 
     else if (i == inputLength - 1) 
     { 
      // == terminator 
      outputBytes[outputLength++] = lookup[(inputBytes[i] & 0xFC) >> 2]; 
      outputBytes[outputLength++] = lookup[(inputBytes[i] & 0x03) << 4]; 
      outputBytes[outputLength++] = '='; 
      outputBytes[outputLength++] = '='; 
     } 

     if (outputLength >= 4) 
     { 
      //truncate data to match actual output length 
      outputBytes = realloc(outputBytes, (NSUInteger)outputLength); 
      return [[NSString alloc] initWithBytesNoCopy:outputBytes 
                length:(NSUInteger)outputLength 
               encoding:NSASCIIStringEncoding 
              freeWhenDone:YES]; 
     } 
     else if (outputBytes) 
     { 
      free(outputBytes); 
     } 
     return nil; 
    } 
+1

Non voglio codificare base64, ho bisogno dei byte grezzi come una stringa – quantumpotato

+1

come ho detto prima base64 è più sicuro perché a volte carattere speciale causerà la decodifica da morsi a stringa per restituire nill – rob180

+1

Ma ho bisogno assolutamente dei bit grezzi. Quindi convertiresti di nuovo in NSString? – quantumpotato

6
  1. Il motivo della stringa viene considerato 'inaffidabile' in post precedenti Stack è perché anche loro stavano tentando di utilizzare oggetti NSData dove i byte che terminano non sono adeguatamente terminato con NULL:

    NSString *jsonString = [NSString stringWithUTF8String:[nsDataObj bytes]]; 
    // This is unreliable because it may result in NULL string values 
    
  2. considerando che l'esempio che segue dovrebbe dare i risultati desiderati perché la stringa di byte NSData terminerà correttamente:

    NSString *jsonString = [[NSString alloc] initWithBytes:[nsDataObj bytes] length:[nsDataObj length] encoding: NSUTF8StringEncoding]; 
    

Tu eri sulla strada giusta e spero che questo è in grado di aiutarvi a risolvere i problemi presenti. Buona fortuna!

~ ~ EDIT

Assicurarsi che si sta dichiarando il vostro oggetto NSData da un'immagine in questo modo:

NSData *imageData = [[NSData alloc] init]; 
imageData = UIImagePNGRepresentation(yourImage); 
+1

Darò a questo uno scatto. – quantumpotato

+1

Sei riuscito a farlo funzionare? – ChrisHaze

+1

Hey @chrishaze, ottengo una stringa nil da questo :( – quantumpotato

3

terminazione Null non è l'unico problema durante la conversione NSData-NSString.

NSString non è progettato per contenere dati binari arbitrari. Si aspetta una codifica.

Se NSData contiene una sequenza UTF-8 non valida, initializing the NSString will fail.

La documentazione non è del tutto chiaro su questo punto, ma per initWithData che dice:

Restituisce nulle se l'inizializzazione non riesce per qualche motivo (ad esempio se i dati non rappresentano dati validi per la codifica) .

Inoltre: la specifica JSON definisce una stringa come sequence of Unicode characters.

Ciò significa che anche se è possibile ottenere i dati grezzi in una stringa JSON, l'analisi potrebbe non riuscire sul lato ricevente se il codice esegue la convalida UTF-8.

Se non si desidera utilizzare Base64, take a look at the answers here.

3

Tutti i codici di questa risposta sono frammenti di pseudo-codice, è necessario convertire gli algoritmi in Objective-C o in un'altra lingua.

La tua domanda solleva molte domande ... si inizia con:

Ho un oggetto NSData. Devo convertire i suoi byte in una stringa e inviarli come JSON. la descrizione restituisce hex ed è inaffidabile (secondo vari manifesti SO).

Questo sembra suggerire che si desidera codificare i byte come una stringa, pronto per la decodifica di nuovo al byte all'altra estremità. Se questo è il caso si dispone di una serie di scelte, come ad esempio Base 64 codifica ecc Se si desidera qualcosa di semplice che si può solo codificare ogni byte come valore esadecimale a due caratteri, pseudo codice contorno:

NSMutableString *encodedString = @"".mutableCopy; 
foreach aByte in byteData 
    [encodedString appendFormat:@"%02x", aByte]; 

Il il formato %02x indica due cifre esadecimali con padding zero. Ciò si traduce in una stringa che può essere inviata come JSON e decodificata facilmente dall'altra parte. La dimensione del byte sul filo sarà probabilmente pari a con una lunghezza doppia rispetto al byte in cui UTF-8 è la codifica consigliata per JSON sul filo.

Tuttavia, in risposta a una delle risposte si scrive:

ma ho bisogno assolutamente i bit prime.

Cosa intendi con questo? Il tuo ricevitore interpreterà la stringa JSON che ottiene come una sequenza di byte grezzi? Se è così, hai un numero di problemi da affrontare. Le stringhe JSON sono un sottoinsieme di stringhe JavaScript e sono memorizzate come UCS-2 o UTF-16, ovvero sono sequenze di valori a 16 bit e non di valori a 8 bit. Se codifichi ciascun byte in un carattere in una stringa, verrà rappresentato utilizzando 16 bit, se il tuo ricevitore può accedere al flusso di byte deve saltare sempre un altro byte. Naturalmente se il ricevitore accede alle stringhe un carattere alla volta, ogni carattere di 16 bit può essere troncato su un byte di 8 bit. Ora si potrebbe pensare che se si segue questo approccio, ogni byte di 8 bit può essere emesso come carattere come parte di una stringa, ma ciò non funzionerà. Mentre tutti i valori 1-255 sono punti codice Unicode validi e JavaScript/JSON consentono NUL (valore 0) nelle stringhe, non tutti i valori sono stampabili, non è possibile inserire una virgola doppia " in una stringa senza sfuggirli e la fuga carattere è \ - tutti questi dovranno essere codificati nella stringa.Faresti finisce con qualcosa di simile:

NSMutableString *encodedString = @"".mutableCopy; 
foreach aByte in byteData 
    if (isprint(aByte) && aByte != '"' && aByte != '\\') 
     [encodedString appendFormat:@"%c", aByte]; 
    otherwise 
     [encodedString appendFormat:@"\\u00%02x", aByte]; // JSON unicode escape sequence 

Questo produrrà una stringa che quando analizzato da un decoder JSON vi darà un carattere (16-bit) per ogni byte, i primi 8 bit di essere pari a zero. Tuttavia se si passa questa stringa a un encoder JSON sarà codificare le sequenze di escape Unicode, che sono già codificati ... Così si ha realmente bisogno di inviare questa stringa oltre il filo da soli per evitare questo ...

Confuso ? Diventando complicato? Bene, perché stai cercando di inviare dati di byte binari come una stringa? Non dici mai qual è il tuo obiettivo di alto livello o cosa, se non altro, è noto sui dati di byte (ad esempio rappresenta carattere in qualche codifica)

Se questo è davvero solo un array di byte, perché non inviarlo come matrice di numeri JSON - un byte è solo un numero compreso tra 0 e 255. Per fare questo è necessario utilizzare il codice lungo le linee di:

NSMutableArray *encodedBytes = [NSMutableArray new]; 
foreach aByte in byteData 
    [encodedBytes addObject:@(aByte)]; // add aByte as an NSNumber object 

Ora passano encodedBytes-NSJSONSerialisation e invierà una matrice JSON di numeri attraverso il cavo, il ricevitore invertire il processo di confezionamento ogni byte di nuovo in un byte buffer e hai indietro i tuoi byte.

Questo metodo evita tutti i problemi di stringhe, codifiche e fughe valide.

HTH

+0

Sto tentando di inviare dati binari perché questo è ciò che richiede l'API. Viene inviato come corpo della richiesta. – quantumpotato

+0

Quale API richiede i dati binari? Se si trova sul ricevitore e si sta tentando di invocarlo passando i dati come JSON, è sufficiente codificare i dati binari * in qualche modo * mentre viaggiano sul filo come parte della comunicazione. Non è necessario * per codificarlo come una stringa, ma tu puoi. O la prima soluzione, che codifica come una stringa esadecimale o base 64, o l'ultima soluzione, che codifica come una matrice di numeri, soddisferà le tue esigenze.Se i dati sono grandi, potresti voler scegliere base-64 come il metodo più semplice e compatto, ma altrimenti lo faranno. HTH – CRD

+0

Nota che si dice "inviato come corpo della richiesta", questo suggerisce che si sta tentando di comunicare con un servizio Web e si dispone di alcune specifiche di ciò che si aspetta, a differenza di un codice basato sul server che chiama alcune API. In questo caso, è necessario fornire maggiori dettagli nella domanda sull'API e sulle sue aspettative: nessuna API dovrebbe richiedere dati binari in JSON senza specificare come codificarla: JSON non ha dati binari come tipo di dati di base. – CRD