问题
I need to asynchronously decrypt a large file with RNCryptor on iOS (so as to show a progress bar). I have found no example anywhere, and thus have tried what I guessed was right, but... what I've come up with doesn't work : the decryptor’s handler is never called, and the thread crashed with EXC_BAD_ADDRESS after sending all data at the end of the function.
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];
(Obvsiouly, tempPath
is the path to the crypted file ; decryptedPath
is the path where decrypted data should be written).
Also I'm new to ARC so this may be a memory- or dispatch-related problem.
Thanks for any help.
回答1:
I ran into the same issue today, and it seems to be happening due to the recent deprecation of dispatch_get_current_queue() in iOS6.
By changing [RNCryptor initWithHandler:] to create a new queue the decryption works correctly.
NSString *responseQueueName = [@"net.robnapier.response." stringByAppendingString:NSStringFromClass([self class])];
_responseQueue = dispatch_queue_create([responseQueueName UTF8String], NULL);
You can find the fix and an associated unit test (based on your code) on the async_decrypt branch of my fork on github.
Commit on csteynberg/RNCryptor
回答2:
your behaviour is due to asynchronous execution: you call [decryptor finish] before doing the calls to addData: To fix this you should replace
while (cryptedStream.hasBytesAvailable)
{
//...
by
while (YES) {
if (!cryptedStream.hasBytesAvailable) {
dispatch_async(dispatch_get_main_queue(), ^{
[decryptor finish];
});
break;
}
//...
(and of course remove the existing call to [decryptor finish]) this way finish is always called after all the data was sent.
Regards
来源:https://stackoverflow.com/questions/14382969/asynchronously-decrypt-a-large-file-with-rncryptor-on-ios