Как мне выполнить кодировку base64 на iOS?

Я хотел бы выполнить base64 кодирование и декодирование, но я не нашел поддержки со стороны iPhone SDK. Как я могу выполнять base64 кодирование и декодирование с библиотекой или без нее?


person BlueDolphin    schedule 25.12.2008    source источник
comment
Ссылка @GregBernhardt мертва.   -  person Cœur    schedule 08.06.2018


Ответы (18)


Это хороший вариант использования категорий в Objective C.

Для кодировки 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

Для декодирования 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
person Alex Reynolds    schedule 29.04.2009
comment
Если Obj-C чем-то похож на C, вы сможете это сделать: static char base64EncodingTable [64] = ABCDE [etc] 789 + /; - person Artelius; 05.05.2009
comment
при использовании base64StringFromData должна ли длина быть длиной NSData? Я получаю только первые 4 символа, используя длину NSData. Спасибо - person Larry Hipp; 10.06.2009
comment
Я понял, почему я получал только 4 символа ... Перед возвратом цикла while () должен быть}. Я бы отредактировал это, но похоже, что я не могу. - person Larry Hipp; 11.06.2009
comment
он показывает ошибку error: ожидаемое выражение перед 'else' ошибка: ожидаемое выражение перед 'end' - person Mahesh Babu; 27.12.2010
comment
Да, это не работает - put, помимо прочего, не объявлен в base64StringFromData ... - person xil3; 22.06.2011
comment
В base64DataFromString: анализатор xcode говорит, что есть проблемы с двумя строками с inbuf[n] &. Он говорит, что левый операнд '&' является мусорным значением. Я не вижу проблемы с этим кодом, и поэтому я склонен думать, что это ошибка анализатора, но мне интересно, видит ли кто-нибудь проблему с кодом. - person ThomasW; 16.08.2011
comment
Это не ошибка анализатора. Обратите внимание, что код также пытается получить доступ к inbuf [3], который находится за пределами этого массива. Этот код воняет. - person Mike Weller; 08.11.2011
comment
Ниже приведены гораздо более быстрые решения, которые я бы рекомендовал использовать вместо этого. - person Joshua Cohen; 31.03.2012
comment
Что означает значение длины? - person MegaManX; 20.06.2012
comment
Начиная с iOS7 Apple представила свой собственный метод кодирования base 64. См. Ответ Роба ниже, чтобы узнать, как его использовать при сохранении обратной совместимости. - person Code Commander; 07.08.2014

Действительно, очень быстрая реализация, которая была перенесена (и модифицирована / улучшена) из библиотеки PHP Core в собственный код Objective-C, доступна в классе QSStrings из библиотеки QSUtilities. . Я провел быстрый тест: для кодирования файла изображения размером 5,3 МБ (JPEG) потребовалось <50 мсек и около 140 мсек для декодирования.

Код для всей библиотеки (включая методы Base64) доступен на GitHub. .

Или, в качестве альтернативы, если вы хотите, чтобы код только использовал сами методы Base64, я разместил его здесь:

Во-первых, вам понадобятся таблицы сопоставления:

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

Для кодирования:

+ (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;
}

Для декодирования:

+ (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;
}
person Mike Ho    schedule 18.01.2011
comment
Наконец-то правильная и действенная реализация. Спасибо. Другой код здесь меня пугает. - person Mike Weller; 08.11.2011
comment
Кажется, утечка памяти, выделенной как strResult в кодировщике; ему просто нужен free() в конце (перед возвратом, но после NSString stringWithCString) - person JosephH; 25.11.2011
comment
В вашем методе encodeBase64WithData:, разве первый параметр в вызове calloc() не нужно увеличивать на 1, чтобы учесть нулевой терминатор ('\0'), который вы добавляете в конце? - person erikprice; 31.01.2012
comment
Тот факт, что яблоко не дает этого, заставляет Бога убивать котят ... многих из них ... - person dsingleton; 18.05.2012
comment
Я использую это некоторое время, и казалось, что он отлично работает, пока я не начал получать некоторые ошибки, связанные с повреждением памяти, и, используя охранный malloc, я сузил его до этой строки: * objPointer = '\ 0'; так что будьте осторожны, если вы используете это в своих собственных приложениях. - person Mattia; 20.07.2012
comment
Для большей эффективности попробуйте NSData* objData = [NSData dataWithBytesNoCopy:objResult length:j freeWhenDone:YES] - person rvalue; 24.09.2012
comment
Спасибо за разъяснение! Кровавый плагиат распространен в этих блогах ... :) - person t0mm13b; 03.05.2013
comment
Начиная с iOS7 Apple представила свой собственный метод кодирования base 64. См. Ответ Роба ниже, чтобы узнать, как его использовать при сохранении обратной совместимости. - person Code Commander; 07.08.2014
comment
Лучший ответ для кодирования Base64 без проблем с памятью .. Большое спасибо - person Mani murugan; 17.09.2015

В то время, когда этот вопрос был первоначально опубликован, люди по понятным причинам направляли вас к сторонним библиотекам base 64 из-за отсутствия каких-либо собственных подпрограмм. Но iOS 7 представила подпрограммы кодирования base 64 (которые на самом деле просто предоставляют частные методы, которые iOS вернулись к iOS 4).

Итак, вы можете использовать NSData метод base64EncodedStringWithOptions:, чтобы создать строку base-64 из NSData.

NSString *string = [data base64EncodedStringWithOptions:kNilOptions];

И вы можете использовать initWithBase64EncodedString:options: для преобразования базового 64 строка обратно в NSData:

NSData *data = [[NSData alloc] initWithBase64EncodedString:string options:kNilOptions]; 

Или в Swift:

let string = data.base64EncodedString()

И

let data = Data(base64Encoded: string)
person Rob    schedule 05.11.2013
comment
Спасибо, Роб. Не могли бы вы вкратце рассказать о том, что вы написали, ... и раскрывает ранее частные методы iOS 4? - person phi; 28.01.2014
comment
Жаль, что этот ответ скрыт под всеми этими кастомными реализациями. Это слабое место SO, где более подходящее решение могло появиться спустя много времени после того, как был задан исходный вопрос, теперь это решение должно конкурировать с тем, что было принято ранее. - person jakev; 15.03.2014
comment
Вот почему всегда полезно голосовать за более свежие правильные ответы :) - person Steve Wilford; 22.06.2015
comment
почему, черт возьми, такие ответы не на высоте :(, я потратил много времени на обработку всех ответов выше T__T - person Alsh compiler; 03.07.2016
comment
@Rob, как вы относитесь к редактированию этого, чтобы удалить ссылки на iOS 4 (!!) и iOS 7, поскольку Xcode в наши дни даже не может настроить таргетинг ни на одну из них? Я думал сделать это сам, но подумал, что вы, возможно, предпочтете. :) Бонусные баллы за включение быстрого примера кода ... - person Abhi Beckert; 10.09.2020
comment
Я собираюсь оставить ссылки на iOS для исторических целей (в противном случае люди будут сбиты с толку всеми этими ответами о том, как это сделать вручную) и не аннулировать комментарии выше. Но я упростил свой ответ (поскольку условная логика для версий iOS до iOS 7 больше не актуальна; люди могут посмотреть предыдущая версия, если интересно). - person Rob; 10.09.2020

iOS включает встроенную поддержку кодирования и декодирования base64. Если вы посмотрите на resolv.h, вы увидите две функции b64_ntop и b64_pton. Библиотека Square SocketRocket представляет собой разумный пример того, как использовать эти функции из objective-c.

Эти функции довольно хорошо протестированы и надежны - в отличие от многих реализаций, которые вы можете найти в случайных публикациях в Интернете. Не забудьте указать ссылку на libresolv.dylib.

person quellish    schedule 19.04.2013
comment
Потрясающий; намного лучше, чем случайный интернет-сайт! Если кого-то беспокоит использование этих скудно документированных функций, вы можете увидеть их источник на сайте Apple. - person Jesse Rusak; 20.04.2013
comment
Этот парень дает дополнительную информацию об этом: blog.montgomerie.net/ios-hidden -base64-подпрограммы - person Mike; 05.02.2014

Поскольку это, кажется, лучший успех Google по кодировке base64 и iphone, мне захотелось поделиться своим опытом с приведенным выше фрагментом кода.

Это работает, но очень медленно. Тест на случайном изображении (0,4 мб) занял 37 секунд на родном iphone. Основная причина, вероятно, заключается во всей магии ООП - одиночных char NSStrings и т. Д., Которые автоматически выпускаются только после завершения кодирования.

Другое предложение, опубликованное здесь (ab), использует библиотеку openssl, что тоже кажется излишним.

Приведенный ниже код занимает 70 мс - это ускорение в 500 раз. Это только кодирование base64 (декодирование последует, как только я его встречу)

+ (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;
}

Я не учел обрезку линий, так как она мне не нужна, но добавить ее тривиально.

Для тех, кто заинтересован в оптимизации: цель - минимизировать то, что происходит в основном цикле. Следовательно, вся логика обработки последних 3 байтов обрабатывается вне цикла.

Также попробуйте работать с данными на месте, без дополнительного копирования в / из буферов. И сведите любую арифметику к минимуму.

Обратите внимание, что биты, которые собираются вместе для поиска записи в таблице, не будут перекрываться, когда они должны быть объединены вместе без сдвига. Поэтому серьезным улучшением могло бы стать использование 4 отдельных таблиц поиска по 256 байт и устранение сдвигов, например:

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];

Конечно, вы могли бы пойти намного дальше, но это выходит за рамки здесь.

person mvds    schedule 03.05.2010
comment
Хм. Я не мог заставить это работать. Я наблюдаю кодировку base64, отличную от ожидаемой. Вы проверяли это на примерах из RFC 4648? tools.ietf.org/html/rfc4648 - person Alex Reynolds; 07.05.2010
comment
Не знаете, на что ссылаются base64EncodingTable1, base64EncodingTable2, base64EncodingTable3 и base64EncodingTable4? - person Jamie Chapman; 31.07.2010
comment
Очень полезно, но может читать за пределами входного буфера. Когда (left == 2), raw [inp + 2] будет на один байт после конца tmpbuf. Я думаю, что строка должна быть такой: if (left == 2) outbuf [outp ++] = base64EncodingTable [((raw [inp + 1] & 0x0F) ‹< 2)]; - person John Lemberger; 15.11.2010
comment
измените следующую строку ‹code› char tmpbuf [2] = {0,0}; ‹/code› на ‹code› символ без знака tmpbuf [3] = {0,0,0}; ‹/code› - person Satya; 11.04.2011

В отличном улучшении mvds есть две проблемы. Измените код на этот:

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++] = '=';
person user335742    schedule 07.05.2010

Лучшее решение:

В NSData есть встроенная функция

[data base64Encoding]; //iOS < 7.0
[data base64EncodedStringWithOptions:NSDataBase64Encoding76CharacterLineLength]; //iOS >= 7.0
person Nagaraj    schedule 21.10.2013
comment
Мы можем сделать это на основе версии iOS, на которой работает приложение, используя [[UIDevice currentDevice] systemVersion] .floatValue. - person Nagaraj; 24.10.2013
comment
1. Это не скажет вам, с каким SDK вы связались, это проверка во время выполнения. 2. Это прямо противоречит рекомендациям Apple. Вы должны проверять наличие функции, а не версию системы. - person quellish; 24.10.2013

Рад, что людям понравилось. Я должен признать, что финальная стадия была немного некорректной. Помимо правильной установки inp = 0, вы должны также увеличить размер tmpbuf до 3, например

unsigned char tmpbuf[3] = {0,0,0};

или исключить исходное значение [inp + 2]; если бы у нас было необработанное [inp + 2]! = 0 для этого фрагмента, мы, конечно, все равно были бы в цикле ...

В любом случае, вы можете подумать о том, чтобы конечный блок поиска в таблице оставался идентичным блоку в цикле для ясности. В финальной версии, которую я использовал, я сделал

while ( outp%4 ) outbuf[outp++] = '=';

Чтобы добавить ==

Извините, я не проверил RFC и прочее, надо было сделать лучше!

person mvds    schedule 06.07.2010
comment
у вас уже есть учетная запись здесь, поскольку ваш предыдущий ответ на самом деле является другой учетной записью. Кроме того, это должно быть либо редактирование, либо комментарий. - person Alastair Pitts; 06.07.2010
comment
@alastair, похоже, вы получаете аккаунт каждый раз, когда публикуете ответ без регистрации после очистки файлов cookie. Мне не удалось подключиться к своей первой учетной записи (даже с тем же адресом электронной почты и IP), поэтому я просто поместил его в качестве нового ответа, извините за это. - только что зарегистрировались! - person mvds; 09.07.2010
comment
Есть ли шанс отредактировать этот ответ на свой предыдущий, чтобы получить окончательно правильную версию? Спасибо! - person JosephH; 20.10.2011

В iOS8 и более поздних версиях используйте - (NSString *)base64EncodedStringWithOptions:(NSDataBase64EncodingOptions)options из NSData

person AlexeyVMP    schedule 11.08.2015

Чтобы обновить использование методов категории NSData (NSDataBase64Encoding) в iOS7, см. Мой ответ здесь: https://stackoverflow.com/a/18927627/1602729 < / а>

person Damien Pontifex    schedule 21.09.2013

Вот компактная версия Objective-C в виде категории на NSData. Нужно подумать о ...

@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

Если требуется, можно добавить заполнение, расширив область действия 'byt' и добавив 'dest' с (2-байтовыми) символами "=" перед возвратом.

Затем в NSString можно добавить категорию, таким образом:

@implementation NSString (StringUtils)

- (NSString *)newStringInBase64FromString
{
 NSData *theData = [NSData dataWithBytes:[self UTF8String] length:[self length]]; 

 return [theData newStringInBase64FromData];
}

@end
person Community    schedule 10.11.2010

В iOS были встроенные методы кодирования и декодирования Base64 (без использования libresolv), начиная с iOS 4. Однако они были объявлены только в iOS 7 SDK. В документации Apple указано, что вы можете использовать его при таргетинге на iOS 4 и выше.

NSData *myData = ... some data
NSString *base64String = [myData base64Encoding];
NSData *decodedData = [[NSData alloc] initWithBase64Encoding:base64String];
person user102008    schedule 30.12.2013

Вот пример преобразования объекта NSData в Base 64. Он также показывает, как пойти другим путем (декодировать объект NSData в кодировке 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];
person John Muchow    schedule 25.01.2014

в iOS 7

        NSData *data=[[NSData alloc]init];
        [data base64Encoding];
person Mani    schedule 06.02.2014
comment
Нагарадж уже упоминал об этом. См. Его сообщение и комментарии к нему, в которых говорится, что он существует с iOS 4. - person jww; 06.02.2014

Я сделал это с помощью следующего класса ..

@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

Во время звонка звоните

 [Base64Converter base64StringFromData:dataval length:lengthval];

Вот и все...

person Durai Amuthan.H    schedule 10.07.2013

Думаю, это будет полезно

 + (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];

}

person Mrug    schedule 29.01.2014
comment
NSStringUtil? Пожалуйста, дайте исчерпывающий ответ? - person Mohsin Khubaib Ahmed; 05.09.2015
comment
Это два метода, которые вам нужно написать в любом классе, и вы можете вызвать его и передать String instaces в качестве параметра. - person Mrug; 07.09.2015

Загрузите Base64.

Выполните следующий код для преобразования изображения в base64

NSString *base64String=[UIImagePNGRepresentation(image) base64Encoding];
person Pankaj Wadhwa    schedule 10.09.2013

В соответствии с вашими требованиями я создал образец демонстрации с использованием Swift 4, в котором вы можете кодировать / декодировать строку и изображение в соответствии с вашими требованиями.

  • Я также добавил образцы методов соответствующих операций.

    //
    //  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
        }
    
    
    }
    
person iOS Team    schedule 10.01.2018