我想进行base64编码和解码,但我无法从iPhone SDK中找到任何支持。我怎么能做base64编码和解码与或没有一个库?


当前回答

在这个问题最初发布的时候,人们可以理解地引导您使用第三方base64库,因为缺乏任何本地例程。但iOS 7引入了base64编码例程(这实际上只是暴露了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()

And

let data = Data(base64Encoded: string)

其他回答

下面是一个将NSData对象转换为base64的例子。它还展示了如何以另一种方式(解码一个base64编码的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];

很高兴人们喜欢它。我必须承认,最后的游戏有点瑕疵。除了正确地设置inp=0之外,您还应该将tmpbuf的大小增加到3

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

或者省略raw[inp+2]的环;如果我们对这个块有一个原始的[inp+2] != 0,当然我们仍然在循环中……

无论哪种方法都可行,为了清晰起见,您可以考虑保持最终的表查找块与循环中的表查找块相同。在最后的版本中,我使用了

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

添加==

对不起,我没有检查RFC之类的东西,应该做得更好!

在这个问题最初发布的时候,人们可以理解地引导您使用第三方base64库,因为缺乏任何本地例程。但iOS 7引入了base64编码例程(这实际上只是暴露了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()

And

let data = Data(base64Encoded: string)

因为这似乎是在base64编码和iphone上排名第一的谷歌,我想用上面的代码片段分享我的经验。

它是有效的,但是非常慢。在本机iphone上对随机图像(0.4 mb)进行基准测试需要37秒。主要原因可能是OOP的魔力——单字符nsstring等,只有在编码完成后才会自动释放。

这里发布的另一个建议(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];

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

更好的解决方案:

NSData中有一个内置函数

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