调度队列和异步RNCryptor [英] Dispatch queues and asynchronous RNCryptor

查看:224
本文介绍了调度队列和异步RNCryptor的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是对异步解密大型文件的后续行动在iOS上使用RNCryptor的文件

我已经设法使用本文中描述的方法异步解密大型下载文件(60Mb),由Calman更正在他的回答中。

I've managed to asynchronously decrypt a large, downloaded file (60Mb) with the method described in this post, corrected by Calman in his answer.

它基本上是这样的:

int blockSize = 32 * 1024;
NSInputStream *cryptedStream = [NSInputStream inputStreamWithFileAtPath:...];
NSOutputStream *decryptedStream = [NSOutputStream output...];

[cryptedStream open];
[decryptedStream open];

RNDecryptor *decryptor = [[RNDecryptor alloc] initWithPassword:@"blah" handler:^(RNCryptor *cryptor, NSData *data) {
    NSLog("Decryptor recevied %d bytes", data.length);
    [decryptedStream write:data.bytes maxLength:data.length];
    if (cryptor.isFinished) {
        [decryptedStream close];
        // call my delegate that I'm finished with decrypting
    }
}];

while (cryptedStream.hasBytesAvailable) {
    uint8_t buf[blockSize];
    NSUInteger bytesRead = [cryptedStream read:buf maxLength:blockSize];
    NSData *data = [NSData dataWithBytes:buf length:bytesRead];

    [decryptor addData:data];
    NSLog("Sent %d bytes to decryptor", bytesRead);
}

[cryptedStream close];
[decryptor finish];

但是,我仍然面临一个问题:在解密之前,整个数据都会加载到内存中。我可以看到一堆发送X字节到解密器,然后,在控制台中同一堆Decryptor接收X字节,当我想看到发送,接收,发送,接收,... 。。

However, I'm still facing a problem: the whole data is loaded in memory before being decrypted. I can see a bunch of "Sent X bytes to decryptor", and after that, the same bunch of "Decryptor recevied X bytes" in the console, when I'd like to see "Sent, received, sent, receives, ...".

这对于小型(2Mb)文件或模拟器上的大型(60Mb)文件来说很好;但是在真正的iPad1上由于内存限制而崩溃,显然我无法为我的制作应用程序保留此程序。

That's fine for small (2Mb) files, or with large (60Mb) files on simulator; but on a real iPad1 it crashes due to memory constraints, so obviously I can't keep this procedure for my production app.

我觉得我需要发送数据通过使用 dispatch_async 而不是盲目地在中发送循环来解密,但是我完全迷失了。我试过了:

I feel like I need to send the data to the decryptor by using dispatch_async instead of blindly sending it in the while loop, however I'm completely lost. I've tried:


  • 之前创建我自己的队列,同时,并使用 dispatch_async(myQueue,^ {[decryptor addData:data];});

  • 相同,但调度整个代码内部循环

  • 相同,但在循环时调度整个 / li>
  • 使用 RNCryptor -provided responseQueue 而不是我自己的队列

  • creating my own queue before the while, and using dispatch_async(myQueue, ^{ [decryptor addData:data]; });
  • the same, but dispatching the whole code inside of the while loop
  • the same, but dispatching the whole while loop
  • using RNCryptor-provided responseQueue instead of my own queue

这四种变种中没有任何作用。

Nothing works amongst these 4 variants.

我对此并不完全了解调度队列;我觉得问题出在这里。如果有人能对此有所了解,我会很高兴。

I don't have a complete understanding of dispatch queues yet; I feel the problem lies here. I'd be glad if somebody could shed some light on this.

推荐答案

如果你只想一次处理一个块,然后只在第一个块回叫你时处理一个块。你不需要信号量来做到这一点,你只需要在回调中执行下一次读取。您可能需要 readStreamBlock 中的 @autoreleasepool 块,但我认为您不需要它。

If you only want to process one block at a time, then only process a block when the first block calls you back. You don't need a semaphore to do that, you just need to perform the next read inside the callback. You might want an @autoreleasepool block inside of readStreamBlock, but I don't think you need it.

当我有时间时,我可能会将它直接包装到RNCryptor中。我为它打开了第47期问题。我愿意拉取请求。

When I have some time, I'll probably wrap this directly into RNCryptor. I opened Issue#47 for it. I am open to pull requests.

// Make sure that this number is larger than the header + 1 block.
// 33+16 bytes = 49 bytes. So it shouldn't be a problem.
int blockSize = 32 * 1024;

NSInputStream *cryptedStream = [NSInputStream inputStreamWithFileAtPath:@"C++ Spec.pdf"];
NSOutputStream *decryptedStream = [NSOutputStream outputStreamToFileAtPath:@"/tmp/C++.crypt" append:NO];

[cryptedStream open];
[decryptedStream open];

// We don't need to keep making new NSData objects. We can just use one repeatedly.
__block NSMutableData *data = [NSMutableData dataWithLength:blockSize];
__block RNEncryptor *decryptor = nil;

dispatch_block_t readStreamBlock = ^{
  [data setLength:blockSize];
  NSInteger bytesRead = [cryptedStream read:[data mutableBytes] maxLength:blockSize];
  if (bytesRead < 0) {
    // Throw an error
  }
  else if (bytesRead == 0) {
    [decryptor finish];
  }
  else {
    [data setLength:bytesRead];
    [decryptor addData:data];
    NSLog(@"Sent %ld bytes to decryptor", (unsigned long)bytesRead);
  }
};

decryptor = [[RNEncryptor alloc] initWithSettings:kRNCryptorAES256Settings
                                         password:@"blah"
                                          handler:^(RNCryptor *cryptor, NSData *data) {
                                            NSLog(@"Decryptor recevied %ld bytes", (unsigned long)data.length);
                                            [decryptedStream write:data.bytes maxLength:data.length];
                                            if (cryptor.isFinished) {
                                              [decryptedStream close];
                                              // call my delegate that I'm finished with decrypting
                                            }
                                            else {
                                              // Might want to put this in a dispatch_async(), but I don't think you need it.
                                              readStreamBlock();
                                            }
                                          }];

// Read the first block to kick things off    
readStreamBlock();

这篇关于调度队列和异步RNCryptor的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆