title: Memory issues when encrypting/decrypting a large file with RNCryptor on iOS
body: <p>I'm trying to use RNCryptor to encrypt and decrypt large files (600+MB) on iOS. On <a href="https://github.com/rnapier/RNCryptor/blob/master/README.md#async-and-streams" rel="nofollow noreferrer">the github</a> I found example code on how to use the library asynchronously on streams. This code is similar to the answer of Rob Napier on <a href="https://stackoverflow.com/questions/14481605/dispatch-queues-and-asynchronous-rncryptor/14586231#14586231">a question about this same subject</a>. </p>
  
  <p>However, although I think I implemented the code correctly, the app uses up to 1.5 GB of memory (in the iPad 6.1 simulator). I thought the code was supposed to prevent the app from keeping more than one block of data in-memory? So what is going wrong? </p>
  
  <p>In my controller, I create a 'CryptController' which I message with encrypt/decrypt requests. </p>
  
  <pre><code>  // Controller.m
    NSString *password = @"pw123";
    self.cryptor = [[CryptController alloc] initWithPassword:password];
  
    //start encrypting file
    [self.cryptor streamEncryptRequest:self.fileName andExtension:@"pdf" withURL:[self samplesURL]];
  
    //wait for encryption to finish
    NSDate *timeout = [NSDate dateWithTimeIntervalSinceNow:1];
    do {
      [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
                               beforeDate:timeout];
    } while (![self.cryptor isFinished]);
  </code></pre>
  
  <p>In CryptController I have:</p>
  
  <pre><code>- (void)streamEncryptionDidFinish {
    if (self.cryptor.error) {
      NSLog(@"An error occurred. You cannot trust decryptedData at this point");
    }
    else {
      NSLog(@"%@ is complete. Use it as you like", [self.tempURL lastPathComponent]);
    }
    self.cryptor = nil;
    self.isFinished = YES;
  }
  
  - (void) streamEncryptRequest:(NSString *)fileName andExtension:(NSString *)ext withURL:(NSURL *)directory {
  
    //Make sure that this number is larger than the header + 1 block.
    int blockSize = 32 * 1024;
  
    NSString *encryptedFileName = [NSString stringWithFormat:@"streamEnc_%@", fileName];
    self.tempURL = [[NSFileManager defaultManager] URLForDirectory:NSDocumentDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:NO error:nil];
    self.tempURL = [self.tempURL URLByAppendingPathComponent:encryptedFileName isDirectory:NO];
    self.tempURL = [self.tempURL URLByAppendingPathExtension:@"crypt"];
  
    NSInputStream *decryptedStream = [NSInputStream inputStreamWithURL:[[directory URLByAppendingPathComponent:fileName isDirectory:NO] URLByAppendingPathExtension:ext]];
    NSOutputStream *cryptedStream = [NSOutputStream outputStreamWithURL:self.tempURL append:NO];
  
    [cryptedStream open];
    [decryptedStream open];
  
    __block NSMutableData *data = [NSMutableData dataWithLength:blockSize];
    __block RNEncryptor *encryptor = nil;
  
    dispatch_block_t readStreamBlock = ^{
      [data setLength:blockSize];
      NSInteger bytesRead = [decryptedStream read:[data mutableBytes] maxLength:blockSize];
      if (bytesRead &lt; 0) {
        //Throw an error
      }
      else if (bytesRead == 0) {
        [encryptor finish];
      }
      else {
        [data setLength:bytesRead];
        [encryptor addData:data];
        //NSLog(@"Sent %ld bytes to encryptor", (unsigned long)bytesRead);
      }
    };
  
    encryptor = [[RNEncryptor alloc] initWithSettings:kRNCryptorAES256Settings
                                             password:self.password
                                              handler:^(RNCryptor *cryptor, NSData *data) {
                                                //NSLog(@"Encryptor received %ld bytes", (unsigned long)data.length);
                                                [cryptedStream write:data.bytes maxLength:data.length];
                                                if (cryptor.isFinished) {
                                                  [decryptedStream close];
                                                  //call my delegate that i'm finished with decrypting
                                                  [self streamEncryptionDidFinish];
                                                }
                                                else {
                                                  readStreamBlock();
                                                }
                                              }];
  
    // Read the first block to kick things off
    self.isFinished = NO;
    readStreamBlock();
  }
  </code></pre>
  
  <p>When I profile using the Allocation Instrument, the allocation categories I see consistently growing are <code>malloc 32.50 KB</code>, <code>malloc 4.00 KB</code>, <code>NSConcreteData</code> and <code>NSSubrangeData</code>. Especially the <code>malloc 32.50 KB</code> grows big, over 1 GB. The responsible caller is 
  <code>[NSConcreteData initWithBytes:length:copy:freeWhenDone:bytesAreVM:]</code>
  For <code>NSConcreteData</code> the responsible caller is
  <code>-[NSData(NSData) copyWithZone:]</code>.</p>
  
  <p>When I profile using the Leaks Instrument, no leaks are found.</p>
  
  <p>I'm new to Objective-C, and from what I understood, the new ARC is supposed to handle allocation and deallocation of memory. When googling on anything memory related, all the information I find is assuming you don't use ARC (or it didn't exist at time of writing). I sure am using ARC, since I get compile errors saying so when I try to manually deallocate memory. </p>
  
  <p>If anyone can help me with this, it would be greatly appreciated! If any more information is needed, I'll be happy to provide it :)
  Also, I'm new to StackOverflow, so if there's anything I've overlooked that I should have done, kindly inform me!</p>