我需要在iOS上使用RNCryptor异步解密大文件(以显示进度条)。我在任何地方都找不到任何例子,因此我已经尝试了我认为是正确的,但是......我提出的并不起作用:解密器的处理程序从未被调用,并且线程在发送所有数据后与EXC_BAD_ADDRESS崩溃在功能结束时。
NSOutputStream *decryptedStream = [NSOutputStream outputStreamToFileAtPath:decryptedPath append:NO];
[decryptedStream open];
NSUInteger totalBytesToRead = [[[NSFileManager defaultManager] attributesOfItemAtPath:tempPath error:nil] fileSize];
__block NSUInteger totalBytesRead = 0;
LOG("I've got %d bytes to decrypt.", totalBytesToRead);
RNDecryptor *decryptor = [[RNDecryptor alloc] initWithPassword:SNCatalogPassword handler:^(RNCryptor *cryptor, NSData *data) {
totalBytesRead += data.length;
[decryptedStream write:data.bytes maxLength:data.length];
LOG("Decrypted %d bytes : %d / %d bytes treated", data.length, totalBytesRead, totalBytesToRead);
if (cryptor.isFinished)
{
//proceed
LOG("Done with decrypting.");
[decryptedStream close];
}
}];
// Feed data to the decryptor
NSInputStream *cryptedStream = [NSInputStream inputStreamWithFileAtPath:tempPath];
[cryptedStream open];
while (cryptedStream.hasBytesAvailable)
{
uint8_t buf[4096];
NSUInteger bytesRead = [cryptedStream read:buf maxLength:4096];
NSData *data = [NSData dataWithBytes:buf length:bytesRead];
LOG("Sending %d bytes to decryptor...", bytesRead);
dispatch_async(dispatch_get_main_queue(), ^{
[decryptor addData:data];
});
}
LOG("Sent everything.");
[decryptor finish];
[cryptedStream close];
(很明显,tempPath
是加密文件的路径; decryptedPath
是应该写入解密数据的路径。)
此外,我是ARC的新手,因此这可能是与记忆或调度相关的问题。
感谢您的帮助。
答案 0 :(得分:3)
我今天遇到了同样的问题,由于最近在iOS6中弃用了dispatch_get_current_queue(),它似乎正在发生。
通过更改[RNCryptor initWithHandler:]来创建新队列,解密工作正常。
NSString *responseQueueName = [@"net.robnapier.response." stringByAppendingString:NSStringFromClass([self class])];
_responseQueue = dispatch_queue_create([responseQueueName UTF8String], NULL);
您可以在我的fork on github的async_decrypt分支上找到修复程序和相关的单元测试(基于您的代码)。
Commit 上的答案 1 :(得分:2)
您的行为是由异步执行造成的:您在调用 addData:之前调用 [decryptor finish] 要解决此问题,您应该替换
while (cryptedStream.hasBytesAvailable)
{
//...
通过
while (YES) {
if (!cryptedStream.hasBytesAvailable) {
dispatch_async(dispatch_get_main_queue(), ^{
[decryptor finish];
});
break;
}
//...
(当然删除现有的 [decryptor finish] 调用) 这样,在发送完所有数据之后,总是将称为。
此致