我想进行base64编码和解码,但我无法从iPhone SDK中找到任何支持。我怎么能做base64编码和解码与或没有一个库?
当前回答
因为这似乎是在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];
当然,你可以更进一步,但这超出了这里的范围。
其他回答
在这个问题最初发布的时候,人们可以理解地引导您使用第三方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)
在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++] = '=';
iOS从iOS 4开始就有内置的Base64编码和解码方法(不使用libresolv)。然而,它只在iOS 7 SDK中声明。苹果文档指出,你可以在iOS 4及以上系统上使用它。
NSData *myData = ... some data
NSString *base64String = [myData base64Encoding];
NSData *decodedData = [[NSData alloc] initWithBase64Encoding:base64String];
iOS内置了对base64编码和解码的支持。如果你查看resolv.h,你会看到两个函数b64_ntop和b64_pton。Square SocketRocket库提供了一个如何从objective-c中使用这些函数的合理示例。
这些功能都经过了很好的测试和可靠-不像你在网上随便看到的那些实现。 不要忘记链接libresolve .dylib。
很高兴人们喜欢它。我必须承认,最后的游戏有点瑕疵。除了正确地设置inp=0之外,您还应该将tmpbuf的大小增加到3
unsigned char tmpbuf[3] = {0,0,0};
或者省略raw[inp+2]的环;如果我们对这个块有一个原始的[inp+2] != 0,当然我们仍然在循环中……
无论哪种方法都可行,为了清晰起见,您可以考虑保持最终的表查找块与循环中的表查找块相同。在最后的版本中,我使用了
while ( outp%4 ) outbuf[outp++] = '=';
添加==
对不起,我没有检查RFC之类的东西,应该做得更好!
推荐文章
- 如何删除默认的导航栏空间在SwiftUI导航视图
- 如何在iOS中使用Swift编程segue
- Swift -整数转换为小时/分钟/秒
- Swift:声明一个空字典
- 为什么ARC仍然需要@autoreleasepool ?
- 可能增加的最坏的空间使用量是多少?
- 在成功提交我的应用程序后,“太多符号文件”
- 首先添加一个UIView,甚至是导航栏
- 我如何改变UIButton标题颜色?
- 在Swift中如何调用GCD主线程上的参数方法?
- NSLayoutConstraints是可动画的吗?
- iOS -构建失败,CocoaPods无法找到头文件
- Xcode 4挂在“附加到(应用程序名称)”
- CFNetwork SSLHandshake iOS 9失败
- 请求失败:不可接受的内容类型:文本/html使用AFNetworking 2.0