RNCryptor を使用して、iOS で大きなファイル (600 MB 以上) を暗号化および復号化しようとしています。githubで、ストリームでライブラリを非同期的に使用する方法のサンプル コードを見つけました。このコードは、この同じ件名に関する質問に対するRob Napier の回答に似ています。
ただし、コードを正しく実装したと思いますが、アプリは最大 1.5 GB のメモリを使用します (iPad 6.1 シミュレーターで)。このコードは、アプリがメモリ内に複数のデータ ブロックを保持するのを防ぐためのものだと思っていましたか? それで、何がうまくいかないのですか?
私のコントローラーでは、暗号化/復号化要求でメッセージを送る「CryptController」を作成します。
// 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]);
CryptController には次のものがあります。
- (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 < 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();
}
Allocation Instrument を使用してプロファイリングすると、一貫して増加している割り当てカテゴリはmalloc 32.50 KB
、malloc 4.00 KB
、NSConcreteData
およびNSSubrangeData
です。特に はmalloc 32.50 KB
大きくなり、1 GB を超えます。担当の発信
者[NSConcreteData initWithBytes:length:copy:freeWhenDone:bytesAreVM:]
はですNSConcreteData
担当の発信者は
-[NSData(NSData) copyWithZone:]
です。
Leaks Instrument を使用してプロファイリングすると、リークは見つかりません。
私はObjective-Cが初めてで、私が理解したことから、新しいARCはメモリの割り当てと割り当て解除を処理することになっています。メモリに関連するものをグーグルで検索すると、ARCを使用していない(または執筆時点では存在していなかった)と仮定した情報がすべて見つかります。手動でメモリの割り当てを解除しようとするとコンパイルエラーが発生するので、確かにARCを使用しています。
誰かがこれで私を助けることができれば、それは大歓迎です! さらに情報が必要な場合は、喜んで提供させていただきます:) また、私は StackOverflow を初めて使用するので、見落としていることがあれば、お知らせください。