我想进行base64编码和解码,但我无法从iPhone SDK中找到任何支持。我怎么能做base64编码和解码与或没有一个库?
当前回答
这是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
其他回答
iOS内置了对base64编码和解码的支持。如果你查看resolv.h,你会看到两个函数b64_ntop和b64_pton。Square SocketRocket库提供了一个如何从objective-c中使用这些函数的合理示例。
这些功能都经过了很好的测试和可靠-不像你在网上随便看到的那些实现。 不要忘记链接libresolve .dylib。
更好的解决方案:
NSData中有一个内置函数
[data base64Encoding]; //iOS < 7.0
[data base64EncodedStringWithOptions:NSDataBase64Encoding76CharacterLineLength]; //iOS >= 7.0
因为这似乎是在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];
当然,你可以更进一步,但这超出了这里的范围。
我已经做到了使用以下类..
@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];
就是这样……
关于在iOS7中使用NSData (NSDataBase64Encoding)类别方法的更新,请参阅我的回答:https://stackoverflow.com/a/18927627/1602729
推荐文章
- 如何在iOS上进行base64编码?
- 如何停止不必要的UIButton动画标题变化?
- 是否有可能更新一个本地化的故事板的字符串?
- 以编程方式获取Bundle Identifier
- 为iPad和iPhone设计输入按钮
- 如何在我的iPhone应用程序中使用NSError ?
- 我的预发行应用已经在iTunes Connect中“处理”了一周多,这是怎么回事?
- Xcode iOS项目只显示“我的Mac 64位”,但不显示模拟器或设备
- Objective-C中的自动引用计数不能防止或减少什么样的泄漏?
- 在Xcode 9中如何从打开的多个模拟器中退出或关闭单个模拟器?
- 如何使用Swift播放声音?
- UINavigationBar自定义返回按钮没有标题
- 如何精确地以毫秒为单位记录方法的执行时间?
- 在整个UIWindow中获取UIView的位置
- 如何解散ViewController在Swift?