Chciałbym base64
kodować i dekodować, ale nie mogłem znaleźć wsparcia z iPhone'a SDK
. Jak mogę base64
kodować i dekodować z biblioteką lub bez?
Chciałbym base64
kodować i dekodować, ale nie mogłem znaleźć wsparcia z iPhone'a SDK
. Jak mogę base64
kodować i dekodować z biblioteką lub bez?
Odpowiedzi:
Jest to sprawa dobrego wykorzystania na Objective C kategoriach .
W przypadku kodowania Base64:
#import <Foundation/NSString.h>
@interface NSString (NSStringAdditions)
+ (NSString *) base64StringFromData:(NSData *)data length:(int)length;
@end
-------------------------------------------
#import "NSStringAdditions.h"
static char base64EncodingTable[64] = {
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
};
@implementation NSString (NSStringAdditions)
+ (NSString *) base64StringFromData: (NSData *)data length: (int)length {
unsigned long ixtext, lentext;
long ctremaining;
unsigned char input[3], output[4];
short i, charsonline = 0, ctcopy;
const unsigned char *raw;
NSMutableString *result;
lentext = [data length];
if (lentext < 1)
return @"";
result = [NSMutableString stringWithCapacity: lentext];
raw = [data bytes];
ixtext = 0;
while (true) {
ctremaining = lentext - ixtext;
if (ctremaining <= 0)
break;
for (i = 0; i < 3; i++) {
unsigned long ix = ixtext + i;
if (ix < lentext)
input[i] = raw[ix];
else
input[i] = 0;
}
output[0] = (input[0] & 0xFC) >> 2;
output[1] = ((input[0] & 0x03) << 4) | ((input[1] & 0xF0) >> 4);
output[2] = ((input[1] & 0x0F) << 2) | ((input[2] & 0xC0) >> 6);
output[3] = input[2] & 0x3F;
ctcopy = 4;
switch (ctremaining) {
case 1:
ctcopy = 2;
break;
case 2:
ctcopy = 3;
break;
}
for (i = 0; i < ctcopy; i++)
[result appendString: [NSString stringWithFormat: @"%c", base64EncodingTable[output[i]]]];
for (i = ctcopy; i < 4; i++)
[result appendString: @"="];
ixtext += 3;
charsonline += 4;
if ((length > 0) && (charsonline >= length))
charsonline = 0;
}
return result;
}
@end
W przypadku dekodowania Base64:
#import <Foundation/Foundation.h>
@class NSString;
@interface NSData (NSDataAdditions)
+ (NSData *) base64DataFromString:(NSString *)string;
@end
-------------------------------------------
#import "NSDataAdditions.h"
@implementation NSData (NSDataAdditions)
+ (NSData *)base64DataFromString: (NSString *)string
{
unsigned long ixtext, lentext;
unsigned char ch, inbuf[4], outbuf[3];
short i, ixinbuf;
Boolean flignore, flendtext = false;
const unsigned char *tempcstring;
NSMutableData *theData;
if (string == nil)
{
return [NSData data];
}
ixtext = 0;
tempcstring = (const unsigned char *)[string UTF8String];
lentext = [string length];
theData = [NSMutableData dataWithCapacity: lentext];
ixinbuf = 0;
while (true)
{
if (ixtext >= lentext)
{
break;
}
ch = tempcstring [ixtext++];
flignore = false;
if ((ch >= 'A') && (ch <= 'Z'))
{
ch = ch - 'A';
}
else if ((ch >= 'a') && (ch <= 'z'))
{
ch = ch - 'a' + 26;
}
else if ((ch >= '0') && (ch <= '9'))
{
ch = ch - '0' + 52;
}
else if (ch == '+')
{
ch = 62;
}
else if (ch == '=')
{
flendtext = true;
}
else if (ch == '/')
{
ch = 63;
}
else
{
flignore = true;
}
if (!flignore)
{
short ctcharsinbuf = 3;
Boolean flbreak = false;
if (flendtext)
{
if (ixinbuf == 0)
{
break;
}
if ((ixinbuf == 1) || (ixinbuf == 2))
{
ctcharsinbuf = 1;
}
else
{
ctcharsinbuf = 2;
}
ixinbuf = 3;
flbreak = true;
}
inbuf [ixinbuf++] = ch;
if (ixinbuf == 4)
{
ixinbuf = 0;
outbuf[0] = (inbuf[0] << 2) | ((inbuf[1] & 0x30) >> 4);
outbuf[1] = ((inbuf[1] & 0x0F) << 4) | ((inbuf[2] & 0x3C) >> 2);
outbuf[2] = ((inbuf[2] & 0x03) << 6) | (inbuf[3] & 0x3F);
for (i = 0; i < ctcharsinbuf; i++)
{
[theData appendBytes: &outbuf[i] length: 1];
}
}
if (flbreak)
{
break;
}
}
}
return theData;
}
@end
Naprawdę bardzo szybka implementacja, która została przeniesiona (i zmodyfikowana / ulepszona) z biblioteki PHP Core do natywnego kodu Objective-C jest dostępna w klasie QSStrings z biblioteki QSUtilities . Zrobiłem szybki test porównawczy: plik obrazu w formacie 5,3 MB (JPEG) kodował <50 ms, a dekodowanie - około 140 ms.
Kod dla całej biblioteki (w tym metod Base64) jest dostępny na GitHub .
Lub, jeśli chcesz, aby kod był tylko metodami Base64, opublikowałem go tutaj:
Najpierw potrzebujesz tabel mapowania:
static const char _base64EncodingTable[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
static const short _base64DecodingTable[256] = {
-2, -2, -2, -2, -2, -2, -2, -2, -2, -1, -1, -2, -1, -1, -2, -2,
-2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
-1, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, 62, -2, -2, -2, 63,
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -2, -2, -2, -2, -2, -2,
-2, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -2, -2, -2, -2, -2,
-2, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -2, -2, -2, -2, -2,
-2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
-2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
-2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
-2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
-2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
-2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
-2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
-2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2
};
Aby zakodować:
+ (NSString *)encodeBase64WithString:(NSString *)strData {
return [QSStrings encodeBase64WithData:[strData dataUsingEncoding:NSUTF8StringEncoding]];
}
+ (NSString *)encodeBase64WithData:(NSData *)objData {
const unsigned char * objRawData = [objData bytes];
char * objPointer;
char * strResult;
// Get the Raw Data length and ensure we actually have data
int intLength = [objData length];
if (intLength == 0) return nil;
// Setup the String-based Result placeholder and pointer within that placeholder
strResult = (char *)calloc((((intLength + 2) / 3) * 4) + 1, sizeof(char));
objPointer = strResult;
// Iterate through everything
while (intLength > 2) { // keep going until we have less than 24 bits
*objPointer++ = _base64EncodingTable[objRawData[0] >> 2];
*objPointer++ = _base64EncodingTable[((objRawData[0] & 0x03) << 4) + (objRawData[1] >> 4)];
*objPointer++ = _base64EncodingTable[((objRawData[1] & 0x0f) << 2) + (objRawData[2] >> 6)];
*objPointer++ = _base64EncodingTable[objRawData[2] & 0x3f];
// we just handled 3 octets (24 bits) of data
objRawData += 3;
intLength -= 3;
}
// now deal with the tail end of things
if (intLength != 0) {
*objPointer++ = _base64EncodingTable[objRawData[0] >> 2];
if (intLength > 1) {
*objPointer++ = _base64EncodingTable[((objRawData[0] & 0x03) << 4) + (objRawData[1] >> 4)];
*objPointer++ = _base64EncodingTable[(objRawData[1] & 0x0f) << 2];
*objPointer++ = '=';
} else {
*objPointer++ = _base64EncodingTable[(objRawData[0] & 0x03) << 4];
*objPointer++ = '=';
*objPointer++ = '=';
}
}
// Terminate the string-based result
*objPointer = '\0';
// Create result NSString object
NSString *base64String = [NSString stringWithCString:strResult encoding:NSASCIIStringEncoding];
// Free memory
free(strResult);
return base64String;
}
Aby zdekodować:
+ (NSData *)decodeBase64WithString:(NSString *)strBase64 {
const char *objPointer = [strBase64 cStringUsingEncoding:NSASCIIStringEncoding];
size_t intLength = strlen(objPointer);
int intCurrent;
int i = 0, j = 0, k;
unsigned char *objResult = calloc(intLength, sizeof(unsigned char));
// Run through the whole string, converting as we go
while ( ((intCurrent = *objPointer++) != '\0') && (intLength-- > 0) ) {
if (intCurrent == '=') {
if (*objPointer != '=' && ((i % 4) == 1)) {// || (intLength > 0)) {
// the padding character is invalid at this point -- so this entire string is invalid
free(objResult);
return nil;
}
continue;
}
intCurrent = _base64DecodingTable[intCurrent];
if (intCurrent == -1) {
// we're at a whitespace -- simply skip over
continue;
} else if (intCurrent == -2) {
// we're at an invalid character
free(objResult);
return nil;
}
switch (i % 4) {
case 0:
objResult[j] = intCurrent << 2;
break;
case 1:
objResult[j++] |= intCurrent >> 4;
objResult[j] = (intCurrent & 0x0f) << 4;
break;
case 2:
objResult[j++] |= intCurrent >>2;
objResult[j] = (intCurrent & 0x03) << 6;
break;
case 3:
objResult[j++] |= intCurrent;
break;
}
i++;
}
// mop things up if we ended on a boundary
k = j;
if (intCurrent == '=') {
switch (i % 4) {
case 1:
// Invalid state
free(objResult);
return nil;
case 2:
k++;
// flow through
case 3:
objResult[k] = 0;
}
}
// Cleanup and setup the return NSData
NSData * objData = [[[NSData alloc] initWithBytes:objResult length:j] autorelease];
free(objResult);
return objData;
}
strResult
w enkoderze wydaje się przeciekać; potrzebuje tylko free()
na końcu (przed powrotem, ale później NSString stringWithCString
)
encodeBase64WithData:
metodzie pierwszy parametr w wywołaniu nie calloc()
musi być zwiększany o 1, aby uwzględnić terminator zerowy ( '\0'
), który dodajesz na końcu?
Historycznie kierowalibyśmy cię do jednej z wielu zewnętrznych bibliotek 64 bazowych (jak omówiono w innych odpowiedziach) w celu konwersji danych binarnych na ciąg 64 bazowy (i wstecz), ale iOS 7 ma teraz natywne kodowanie bazowe 64 (i ujawnia wcześniej prywatne metody iOS 4, na wypadek, gdybyś musiał obsługiwać wcześniejsze wersje iOS).
Zatem do konwersji NSData
na NSString
podstawową reprezentację 64 możesz użyć base64EncodedStringWithOptions
. Jeśli musisz obsługiwać również wersje iOS wcześniejsze niż 7.0, możesz:
NSString *string;
if ([data respondsToSelector:@selector(base64EncodedStringWithOptions:)]) {
string = [data base64EncodedStringWithOptions:kNilOptions]; // iOS 7+
} else {
string = [data base64Encoding]; // pre iOS7
}
Aby przekonwertować bazę 64 z NSString
powrotem NSData
, możesz użyć initWithBase64EncodedString
. Podobnie, jeśli potrzebujesz obsługiwać wersje iOS wcześniejsze niż 7.0, możesz:
NSData *data;
if ([NSData instancesRespondToSelector:@selector(initWithBase64EncodedString:options:)]) {
data = [[NSData alloc] initWithBase64EncodedString:string options:kNilOptions]; // iOS 7+
} else {
data = [[NSData alloc] initWithBase64Encoding:string]; // pre iOS7
}
Oczywiście, jeśli nie potrzebujesz wstecznej kompatybilności z wersjami iOS wcześniejszymi niż 7.0, jest to nawet łatwiejsze, po prostu użyj base64EncodedStringWithOptions
lub initWithBase64EncodedString
, odpowiednio, i nie zawracaj sobie głowy sprawdzaniem czasu działania wcześniejszych wersji iOS. W rzeczywistości, jeśli użyjesz powyższego kodu, gdy twój minimalny cel to iOS 7 lub wyższy, otrzymasz ostrzeżenie kompilatora o przestarzałych metodach. Tak więc, w iOS 7 i nowszych, po prostu konwertujesz na podstawowy ciąg 64 za pomocą:
NSString *string = [data base64EncodedStringWithOptions:kNilOptions];
i wróć z:
NSData *data = [[NSData alloc] initWithBase64EncodedString:string options:kNilOptions];
iOS zawiera wbudowaną obsługę kodowania i dekodowania base64. Jeśli spojrzysz na resolv.h
to powinieneś zobaczyć dwie funkcje b64_ntop
i b64_pton
. Biblioteka Square SocketRocket stanowi rozsądny przykład użycia tych funkcji z celu-c.
Funkcje te są dość dobrze przetestowane i niezawodne - w przeciwieństwie do wielu implementacji, które można znaleźć w losowych publikacjach internetowych. Nie zapomnij o linkowaniu przeciwko libresolv.dylib
.
Ponieważ wydaje się, że jest to hit Google numer jeden w kodowaniu base64 i iPhone, chciałem podzielić się swoim doświadczeniem z powyższym fragmentem kodu.
Działa, ale jest bardzo wolny. Test porównawczy na losowym obrazie (0,4 MB) trwał 37 sekund w przypadku natywnego telefonu iPhone. Głównym powodem jest prawdopodobnie cała magia OOP - pojedyncze znaki NSStrings itp., Które są automatycznie wydawane dopiero po zakończeniu kodowania.
Inna sugestia opublikowana tutaj (ab) korzysta z biblioteki openssl, która również wydaje się przesadna.
Poniższy kod zajmuje 70 ms - to 500-krotne przyspieszenie. Dotyczy to tylko kodowania base64 (dekodowanie nastąpi, gdy tylko go napotkam)
+ (NSString *) base64StringFromData: (NSData *)data length: (int)length {
int lentext = [data length];
if (lentext < 1) return @"";
char *outbuf = malloc(lentext*4/3+4); // add 4 to be sure
if ( !outbuf ) return nil;
const unsigned char *raw = [data bytes];
int inp = 0;
int outp = 0;
int do_now = lentext - (lentext%3);
for ( outp = 0, inp = 0; inp < do_now; inp += 3 )
{
outbuf[outp++] = base64EncodingTable[(raw[inp] & 0xFC) >> 2];
outbuf[outp++] = base64EncodingTable[((raw[inp] & 0x03) << 4) | ((raw[inp+1] & 0xF0) >> 4)];
outbuf[outp++] = base64EncodingTable[((raw[inp+1] & 0x0F) << 2) | ((raw[inp+2] & 0xC0) >> 6)];
outbuf[outp++] = base64EncodingTable[raw[inp+2] & 0x3F];
}
if ( do_now < lentext )
{
char tmpbuf[2] = {0,0};
int left = lentext%3;
for ( int i=0; i < left; i++ )
{
tmpbuf[i] = raw[do_now+i];
}
raw = tmpbuf;
outbuf[outp++] = base64EncodingTable[(raw[inp] & 0xFC) >> 2];
outbuf[outp++] = base64EncodingTable[((raw[inp] & 0x03) << 4) | ((raw[inp+1] & 0xF0) >> 4)];
if ( left == 2 ) outbuf[outp++] = base64EncodingTable[((raw[inp+1] & 0x0F) << 2) | ((raw[inp+2] & 0xC0) >> 6)];
}
NSString *ret = [[[NSString alloc] initWithBytes:outbuf length:outp encoding:NSASCIIStringEncoding] autorelease];
free(outbuf);
return ret;
}
Pominąłem wycinanie linii, ponieważ go nie potrzebowałem, ale dodanie tego jest banalne.
Dla tych, którzy są zainteresowani optymalizacją: celem jest zminimalizowanie tego, co dzieje się w głównej pętli. Dlatego cała logika zajmująca się ostatnimi 3 bajtami jest przetwarzana poza pętlą.
Spróbuj także pracować na danych w miejscu, bez dodatkowego kopiowania do / z buforów. I zredukuj dowolną arytmetykę do absolutnego minimum.
Zauważ, że bity, które są zebrane razem w celu wyszukania wpisu w tabeli, nie nakładałyby się, gdy miały być uporządkowane razem bez przesuwania. Istotnym ulepszeniem może być zatem użycie 4 oddzielnych 256-bajtowych tabel odnośników i wyeliminowanie przesunięć, takich jak to:
outbuf[outp++] = base64EncodingTable1[(raw[inp] & 0xFC)];
outbuf[outp++] = base64EncodingTable2[(raw[inp] & 0x03) | (raw[inp+1] & 0xF0)];
outbuf[outp++] = base64EncodingTable3[(raw[inp+1] & 0x0F) | (raw[inp+2] & 0xC0)];
outbuf[outp++] = base64EncodingTable4[raw[inp+2] & 0x3F];
Oczywiście możesz pójść o wiele dalej, ale nie jest to tutaj możliwe.
W doskonałej poprawie mvds występują dwa problemy. Zmień kod na ten:
raw = tmpbuf;
inp = 0;
outbuf[outp++] = base64EncodingTable[(raw[inp] & 0xFC) >> 2];
outbuf[outp++] = base64EncodingTable[((raw[inp] & 0x03) << 4) | ((raw[inp+1] & 0xF0) >> 4)];
if ( left == 2 ) outbuf[outp++] = base64EncodingTable[((raw[inp+1] & 0x0F) << 2) | ((raw[inp+2] & 0xC0) >> 6)];
else outbuf[outp++] = '=';
outbuf[outp++] = '=';
Lepsze rozwiązanie:
W NSData jest wbudowana funkcja
[data base64Encoding]; //iOS < 7.0
[data base64EncodedStringWithOptions:NSDataBase64Encoding76CharacterLineLength]; //iOS >= 7.0
Cieszę się, że ludziom się to podobało. Muszę przyznać, że gra końcowa była trochę wadliwa. Oprócz prawidłowego ustawienia inp = 0 powinieneś także zwiększyć rozmiar tmpbuf do 3, np
unsigned char tmpbuf[3] = {0,0,0};
lub pomiń orring surowego [inp + 2]; jeśli mielibyśmy surowy [inp + 2]! = 0 dla tej części, nadal bylibyśmy w pętli oczywiście ...
Tak czy inaczej działa, możesz dla zachowania przejrzystości zatrzymać ostatni blok wyszukiwania tabeli identyczny z blokiem w pętli. W ostatecznej wersji, której użyłem, zrobiłem
while ( outp%4 ) outbuf[outp++] = '=';
Aby dodać ==
Przepraszam, że nie sprawdziłem RFC i innych rzeczy, powinienem był wykonać lepszą robotę!
#import "NSDataAdditions.h"
@implementation NSData (NSDataAdditions)
+ (NSData *) base64DataFromString: (NSString *)string {
unsigned long ixtext, lentext;
unsigned char ch, input[4], output[3];
short i, ixinput;
Boolean flignore, flendtext = false;
const char *temporary;
NSMutableData *result;
if (!string)
return [NSData data];
ixtext = 0;
temporary = [string UTF8String];
lentext = [string length];
result = [NSMutableData dataWithCapacity: lentext];
ixinput = 0;
while (true) {
if (ixtext >= lentext)
break;
ch = temporary[ixtext++];
flignore = false;
if ((ch >= 'A') && (ch <= 'Z'))
ch = ch - 'A';
else if ((ch >= 'a') && (ch <= 'z'))
ch = ch - 'a' + 26;
else if ((ch >= '0') && (ch <= '9'))
ch = ch - '0' + 52;
else if (ch == '+')
ch = 62;
else if (ch == '=')
flendtext = true;
else if (ch == '/')
ch = 63;
else
flignore = true;
if (!flignore) {
short ctcharsinput = 3;
Boolean flbreak = false;
if (flendtext) {
if (ixinput == 0)
break;
if ((ixinput == 1) || (ixinput == 2))
ctcharsinput = 1;
else
ctcharsinput = 2;
ixinput = 3;
flbreak = true;
}
input[ixinput++] = ch;
if (ixinput == 4){
ixinput = 0;
output[0] = (input[0] << 2) | ((input[1] & 0x30) >> 4);
output[1] = ((input[1] & 0x0F) << 4) | ((input[2] & 0x3C) >> 2);
output[2] = ((input[2] & 0x03) << 6) | (input[3] & 0x3F);
for (i = 0; i < ctcharsinput; i++)
[result appendBytes: &output[i] length: 1];
}
if (flbreak)
break;
}
}
return result;
}
@end
Aby uzyskać aktualizację w celu użycia NSData (NSDataBase64Encoding)
metod kategorii w iOS7, zobacz moją odpowiedź tutaj: https://stackoverflow.com/a/18927627/1602729
Oto kompaktowa wersja Objective-C jako kategoria na NSData. Trochę myślenia o ...
@implementation NSData (DataUtils)
static char base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
- (NSString *)newStringInBase64FromData
{
NSMutableString *dest = [[NSMutableString alloc] initWithString:@""];
unsigned char * working = (unsigned char *)[self bytes];
int srcLen = [self length];
// tackle the source in 3's as conveniently 4 Base64 nibbles fit into 3 bytes
for (int i=0; i<srcLen; i += 3)
{
// for each output nibble
for (int nib=0; nib<4; nib++)
{
// nibble:nib from char:byt
int byt = (nib == 0)?0:nib-1;
int ix = (nib+1)*2;
if (i+byt >= srcLen) break;
// extract the top bits of the nibble, if valid
unsigned char curr = ((working[i+byt] << (8-ix)) & 0x3F);
// extract the bottom bits of the nibble, if valid
if (i+nib < srcLen) curr |= ((working[i+nib] >> ix) & 0x3F);
[dest appendFormat:@"%c", base64[curr]];
}
}
return dest;
}
@end
W razie potrzeby można dodać dopełnienie, rozszerzając zakres „byt” i dodając „dest” znakami (2-byt) „=” przed powrotem.
Kategorię można następnie dodać do NSString, a zatem:
@implementation NSString (StringUtils)
- (NSString *)newStringInBase64FromString
{
NSData *theData = [NSData dataWithBytes:[self UTF8String] length:[self length]];
return [theData newStringInBase64FromData];
}
@end
iOS ma wbudowane metody kodowania i dekodowania Base64 (bez użycia libresolv) od iOS 4. Zostało to jednak zadeklarowane tylko w zestawie SDK dla iOS 7. Dokumentacja Apple mówi, że możesz jej użyć, gdy celujesz w iOS 4 i wyżej.
NSData *myData = ... some data
NSString *base64String = [myData base64Encoding];
NSData *decodedData = [[NSData alloc] initWithBase64Encoding:base64String];
Oto przykład przekonwertowania obiektu NSData na Base 64. Pokazuje także, jak przejść w drugą stronę (dekodować obiekt NSData zakodowany w base 64):
NSData *dataTake2 =
[@"iOS Developer Tips" dataUsingEncoding:NSUTF8StringEncoding];
// Convert to Base64 data
NSData *base64Data = [dataTake2 base64EncodedDataWithOptions:0];
// Do something with the data...
// Now convert back from Base64
NSData *nsdataDecoded = [base64Data initWithBase64EncodedData:base64Data options:0];
Zrobiłem to przy użyciu następującej klasy ..
@implementation Base64Converter
static char base64EncodingTable[64] = {
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
};
+ (NSString *) base64StringFromData: (NSData *)data length: (int)length {
unsigned long ixtext, lentext;
long ctremaining;
unsigned char input[3], output[4];
short i, charsonline = 0, ctcopy;
const unsigned char *raw;
NSMutableString *result;
lentext = [data length];
if (lentext < 1)
return @"";
result = [NSMutableString stringWithCapacity: lentext];
raw = [data bytes];
ixtext = 0;
while (true) {
ctremaining = lentext - ixtext;
if (ctremaining <= 0)
break;
for (i = 0; i < 3; i++) {
unsigned long ix = ixtext + i;
if (ix < lentext)
input[i] = raw[ix];
else
input[i] = 0;
}
output[0] = (input[0] & 0xFC) >> 2;
output[1] = ((input[0] & 0x03) << 4) | ((input[1] & 0xF0) >> 4);
output[2] = ((input[1] & 0x0F) << 2) | ((input[2] & 0xC0) >> 6);
output[3] = input[2] & 0x3F;
ctcopy = 4;
switch (ctremaining) {
case 1:
ctcopy = 2;
break;
case 2:
ctcopy = 3;
break;
}
for (i = 0; i < ctcopy; i++)
[result appendString: [NSString stringWithFormat: @"%c", base64EncodingTable[output[i]]]];
for (i = ctcopy; i < 4; i++)
[result appendString: @"="];
ixtext += 3;
charsonline += 4;
if ((length > 0) && (charsonline >= length))
charsonline = 0;
}
return result;
}
@end
Podczas połączenia telefonicznego
[Base64Converter base64StringFromData:dataval length:lengthval];
Otóż to...
Myślę, że to będzie pomocne
+ (NSString *)toBase64String:(NSString *)string {
NSData *data = [string dataUsingEncoding: NSUnicodeStringEncoding];
NSString *ret = [data base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength];
return ret;
}
+ (NSString *)fromBase64String:(NSString *)string {
NSData *aData = [string dataUsingEncoding:NSUTF8StringEncoding];
NSData *aDataDecoded = [[NSData alloc]initWithBase64EncodedString:string options:0];
NSString *decryptedStr = [[NSString alloc]initWithData:aDataDecoded encoding:NSUTF8StringEncoding];
return [decryptedStr autorelease];
}
Pobierz Base64
Wykonaj następujący kod, aby przekonwertować obraz na base64
NSString *base64String=[UIImagePNGRepresentation(image) base64Encoding];
Zgodnie z twoim wymaganiem stworzyłem przykładową wersję demo przy użyciu Swift 4, w której możesz zakodować / zdekodować ciąg i obraz zgodnie z wymaganiami.
Dodałem również przykładowe metody odpowiednich operacji.
//
// Base64VC.swift
// SOF_SortArrayOfCustomObject
//
// Created by Test User on 09/01/18.
// Copyright © 2018 Test User. All rights reserved.
//
import UIKit
import Foundation
class Base64VC: NSObject {
//----------------------------------------------------------------
// MARK:-
// MARK:- String to Base64 Encode Methods
//----------------------------------------------------------------
func sampleStringEncodingAndDecoding() {
if let base64String = self.base64Encode(string: "TestString") {
print("Base64 Encoded String: \n\(base64String)")
if let originalString = self.base64Decode(base64String: base64String) {
print("Base64 Decoded String: \n\(originalString)")
}
}
}
//----------------------------------------------------------------
func base64Encode(string: String) -> String? {
if let stringData = string.data(using: .utf8) {
return stringData.base64EncodedString()
}
return nil
}
//----------------------------------------------------------------
func base64Decode(base64String: String) -> String? {
if let base64Data = Data(base64Encoded: base64String) {
return String(data: base64Data, encoding: .utf8)
}
return nil
}
//----------------------------------------------------------------
// MARK:-
// MARK:- Image to Base64 Encode Methods
//----------------------------------------------------------------
func sampleImageEncodingAndDecoding() {
if let base64ImageString = self.base64Encode(image: UIImage.init(named: "yourImageName")!) {
print("Base64 Encoded Image: \n\(base64ImageString)")
if let originaImage = self.base64Decode(base64ImageString: base64ImageString) {
print("originalImageData \n\(originaImage)")
}
}
}
//----------------------------------------------------------------
func base64Encode(image: UIImage) -> String? {
if let imageData = UIImagePNGRepresentation(image) {
return imageData.base64EncodedString()
}
return nil
}
//----------------------------------------------------------------
func base64Decode(base64ImageString: String) -> UIImage? {
if let base64Data = Data(base64Encoded: base64ImageString) {
return UIImage(data: base64Data)!
}
return nil
}
}