【问题标题】:How do I do base64 encoding on iOS?如何在 iOS 上进行 base64 编码?
【发布时间】:2011-10-18 00:14:20
【问题描述】:

我想做base64的编码和解码,但我找不到来自iPhoneSDK的任何支持。 base64 使用或不使用库如何进行编码和解码?

【问题讨论】:

  • @GregBernhardt 链接已失效。

标签: ios objective-c base64


【解决方案1】:

这是 Objective C categories 的一个很好的用例。

对于 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

【讨论】:

  • 如果 Obj-C 与 C 类似,你应该可以这样做:static char base64EncodingTable[64] = "ABCDE[etc]789+/";
  • 我找到了为什么我只得到 4 个字符......在 while() 循环的返回之前需要有一个 }。我会编辑它,但我看起来不能。
  • 这不是分析器错误。请注意,代码还尝试访问超出该数组范围的 inbuf[3]。这段代码很臭。
  • 长度值代表什么?
  • 从 iOS7 开始,Apple 已经公开了他们的原生 base 64 编码方法。请参阅下面 Rob 的回答,了解如何在保持向后兼容性的同时使用它。
【解决方案2】:

QSUtilities 库的 QSStrings 类 中提供了一个非常非常快速的实现,该实现从 PHP 核心库移植(和修改/改进)到本机 Objective-C 代码中 /强>。我做了一个快速的基准测试:一个 5.3MB 的图像 (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;
}

【讨论】:

  • 终于正确高效的实现了。谢谢。这里的一些其他代码让我害怕。
  • 编码器中分配为strResult的内存似乎泄露了;它只需要最后一个free()(在返回之前但在NSString stringWithCString之后)
  • 在您的 encodeBase64WithData: 方法中,对 calloc() 的调用中的第一个参数是否需要增加 1 以说明您在末尾添加的空终止符 ('\0') ?
  • 我已经使用了一段时间,它似乎工作得很好,直到我开始遇到一些与内存损坏相关的错误并使用保护 malloc 我将它缩小到这一行:*objPointer = '\0 ';因此,如果您在自己的应用程序中使用它,请注意。
  • 从 iOS7 开始,Apple 已经公开了他们的原生 base 64 编码方法。请参阅下面 Rob 的回答,了解如何在保持向后兼容性的同时使用它。
【解决方案3】:

在最初发布此问题时,由于缺少任何本机例程,人们将您引导至第三方 base 64 库是可以理解的。但是 iOS 7 引入了base 64 encoding routines(实际上只是暴露了 iOS 可以追溯到 iOS 4 的私有方法)。

因此,您可以使用NSData 方法base64EncodedStringWithOptions:NSData 创建一个base-64 字符串。

NSString *string = [data base64EncodedStringWithOptions:kNilOptions];

您可以使用initWithBase64EncodedString:options: 将base-64 字符串转换回NSData

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

或者,在 Swift 中:

let string = data.base64EncodedString()

let data = Data(base64Encoded: string)

【讨论】:

  • 感谢罗布。您能否简要说明您所写的内容,“...并公开以前私有的 iOS 4 方法”?
  • 很遗憾,这个答案隐藏在所有这些自定义实现之下。这是 SO 的一个弱点,在提出原始问题很久之后,可能已经出现了更合适的解决方案,现在该解决方案必须与以前接受的解决方案竞争。
  • 这就是为什么支持最近的正确答案总是有用的:)
  • 为什么像这样的地狱答案不是最重要的:(,我花了很多时间处理 T__T 以上的所有答案
  • @Rob 您对编辑此内容以删除对 iOS 4 (!!) 和 iOS 7 的引用有何感想,因为这些天 Xcode 甚至不能针对其中任何一个?我考虑过自己做,但认为你可能更愿意。 :) 包含快速示例代码的奖励积分...
【解决方案4】:

iOS 包含对 base64 编码和解码的内置支持。如果您查看resolv.h,您应该会看到b64_ntopb64_pton 这两个函数。 Square SocketRocket 库提供了一个合理的示例,说明如何使用 Objective-c 中的这些函数。

这些功能经过了很好的测试并且非常可靠 - 与您在互联网上随机发布的许多实现不同。 不要忘记链接到libresolv.dylib

【讨论】:

【解决方案5】:

由于这似乎是 google 在 base64 编码和 iphone 上的排名第一,所以我想分享我对上面代码 sn-p 的经验。

它可以工作,但速度非常慢。在原生 iphone 上,随机图像 (0.4 mb) 的基准测试耗时 37 秒。主要原因可能是所有的 OOP 魔法——单字符 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];

当然你可以更进一步,但这超出了这里的范围。

【讨论】:

  • 嗯。我无法让它工作。我观察到与预期值不同的 base64 编码。您是否使用 RFC 4648 中的示例对此进行了测试? tools.ietf.org/html/rfc4648
  • 难以查看 base64EncodingTable1、base64EncodingTable2、base64EncodingTable3 和 base64EncodingTable4 引用的内容?
  • 非常有帮助,但它可以读取超出输入缓冲区的末尾。当 (left==2) 时,raw[inp+2] 将超出 tmpbuf 的末尾一个字节。我认为这行应该是: if ( left == 2 ) outbuf[outp++] = base64EncodingTable[((raw[inp+1] & 0x0F)
  • 将下面这行 char tmpbuf[2] = {0,0}; 改为 unsigned char tmpbuf[3] = {0,0,0};
【解决方案6】:

在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++] = '=';

【讨论】:

    【解决方案7】:

    更好的解决方案:

    NSData中有一个内置函数

    [data base64Encoding]; //iOS < 7.0
    [data base64EncodedStringWithOptions:NSDataBase64Encoding76CharacterLineLength]; //iOS >= 7.0
    

    【讨论】:

    • 我们可以使用“[[UIDevice currentDevice] systemVersion].floatValue”根据应用运行的iOS版本来做到这一点。
    • 1.这不会告诉您链接的 SDK 是什么,即运行时检查。 2. 这与苹果的指导直接背道而驰。您应该检查功能的可用性,而不是系统版本。
    【解决方案8】:

    很高兴人们喜欢它。我必须承认,最后的比赛有点缺陷。除了正确设置 inp=0 之外,您还应该将 tmpbuf 的大小增加到 3,例如

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

    省略 raw[inp+2] 的 orring;如果我们有一个 raw[inp+2] != 0 这个块,我们当然仍然在循环中......

    无论哪种方式都有效,为了清楚起见,您可以考虑将最终的表查找块与循环中的块保持一致。在我使用的最终版本中,我做到了

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

    添加 ==

    对不起,我没有检查 RFC 和其他东西,应该做得更好!

    【讨论】:

    • 您已经有一个帐户,因为您之前的回答实际上是一个不同的帐户。此外,这应该是对此的编辑或评论。
    • @alastair,在清理 cookie 后,每次您发布答案而不注册时,您似乎都会获得一个“帐户”。我无法连接到我的第一个“帐户”(即使使用相同的电子邮件和 IP 地址),所以我只是将其作为新答案放在那里,对此感到抱歉。 -- 刚刚注册!
    • 您是否有机会将此答案编辑到以前的答案中,以便有一个确定的正确版本?谢谢!
    【解决方案9】:

    iOS8及以后使用- (NSString *)base64EncodedStringWithOptions:(NSDataBase64EncodingOptions)options的NSData

    【讨论】:

      【解决方案10】:
      #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
      

      【讨论】:

        【解决方案11】:

        有关在 iOS7 中使用 NSData (NSDataBase64Encoding) 类别方法的更新,请在此处查看我的答案:https://stackoverflow.com/a/18927627/1602729

        【讨论】:

          【解决方案12】:

          这是一个紧凑的 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
          

          如果需要,可以通过扩大 'byte' 的范围并在返回前附加 'dest' 与(2 字节)“=”字符来添加填充。

          然后可以将类别添加到 NSString,因此:

          @implementation NSString (StringUtils)
          
          - (NSString *)newStringInBase64FromString
          {
           NSData *theData = [NSData dataWithBytes:[self UTF8String] length:[self length]]; 
          
           return [theData newStringInBase64FromData];
          }
          
          @end
          

          【讨论】:

            【解决方案13】:

            iOS 从 iOS 4 开始就内置了 Base64 编码和解码方法(不使用 libresolv)。但是,它只在 iOS 7 SDK 中声明。 Apple 文档指出,您可以在针对 iOS 4 及更高版本时使用它。

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

            【讨论】:

              【解决方案14】:

              这是一个将 NSData 对象转换为 Base 64 的示例。它还展示了如何采用另一种方式(解码 base 64 编码的 NSData 对象):

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

              【讨论】:

                【解决方案15】:

                在 iOS 7 中

                        NSData *data=[[NSData alloc]init];
                        [data base64Encoding];
                

                【讨论】:

                • Nagaraj 已经提到了这一点。请参阅他的帖子和伴随它的 cmets,说明它自 iOS 4 以来就存在。
                【解决方案16】:

                我已经使用以下类完成了它..

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

                就是这样……

                【讨论】:

                  【解决方案17】:

                  我认为这会有所帮助

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

                  }

                  【讨论】:

                  • NSStringUtil?请给出完整的答案?
                  • 这是您需要在任何类中编写的两个方法,您可以调用它并将字符串实例作为参数传递。
                  【解决方案18】:

                  下载Base64

                  执行以下代码将图像转换为 base64

                  NSString *base64String=[UIImagePNGRepresentation(image) base64Encoding];
                  

                  【讨论】:

                    【解决方案19】:

                    根据您的要求,我使用 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
                          }
                      
                      
                      }
                      

                    【讨论】:

                      猜你喜欢
                      • 1970-01-01
                      • 2011-09-05
                      • 1970-01-01
                      • 2011-04-16
                      • 1970-01-01
                      • 1970-01-01
                      • 2017-11-11
                      • 2012-10-26
                      相关资源
                      最近更新 更多