gpt4 book ai didi

ios - 在 iOS 上使用 RNCryptor 加密/解密大文件时的内存问题

转载 作者:IT王子 更新时间:2023-10-28 23:34:11 25 4
gpt4 key购买 nike

我正在尝试使用 RNCryptor 在 iOS 上加密和解密大文件 (600+MB)。在 the github我找到了关于如何在流上异步使用库的示例代码。此代码类似于 Rob Napier 在 a question about this same subject 上的回答。 .

然而,虽然我认为我正确地实现了代码,但该应用程序使用了高达 1.5 GB 的内存(在 iPad 6.1 模拟器中)。我认为代码应该阻止应用程序在内存中保留多个数据 block ?那么出了什么问题呢?

在我的 Controller 中,我创建了一个“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();
}

当我使用分配工具进行分析时,我看到的分配类别持续增长是 malloc 32.50 KBmalloc 4.00 KBNSConcreteDataNSSubrangeData。尤其是 malloc 32.50 KB 变得很大,超过 1 GB。负责的来电者是[NSConcreteData initWithBytes:length:copy:freeWhenDone:bytesAreVM:]对于 NSConcreteData 负责的调用者是-[NSData(NSData) copyWithZone:].

当我使用 Leaks Instrument 进行分析时,没有发现任何泄漏。

我是 Objective-C 的新手,据我了解,新的 ARC 应该处理内存的分配和释放。在搜索任何与内存相关的内容时,我发现的所有信息都是假设您不使用 ARC(或者在撰写本文时它不存在)。我确定使用的是 ARC,因为当我尝试手动释放内存时会出现编译错误。

如果有人可以帮助我,将不胜感激!如果需要更多信息,我很乐意提供:)另外,我是 StackOverflow 的新手,所以如果我忽略了我应该做的任何事情,请告诉我!

最佳答案

我终于尝试了 here 给出的解决方案,它使用信号量而不是依赖于回调来等待流。这很完美:) 根据分配工具,内存使用量徘徊在 1.1 MB 左右。由于信号量语法,它可能看起来不那么整洁,但至少它完成了我需要它做的事情。

当然也欢迎其他建议:)

- (void)encryptWithSemaphore:(NSURL *)url {
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);

__block int total = 0;
int blockSize = 32 * 1024;

NSString *encryptedFile = [[url lastPathComponent] stringByDeletingPathExtension];
NSURL *docsURL = [[NSFileManager defaultManager] URLForDirectory:NSDocumentDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:NO error:nil];
self.tempURL = [[docsURL URLByAppendingPathComponent:encryptedFile isDirectory:NO] URLByAppendingPathExtension:@"crypt"];

NSInputStream *inputStream = [NSInputStream inputStreamWithURL:url];
__block NSOutputStream *outputStream = [NSOutputStream outputStreamWithURL:self.tempURL append:NO];
__block NSError *encryptionError = nil;

[inputStream open];
[outputStream open];

RNEncryptor *encryptor = [[RNEncryptor alloc] initWithSettings:kRNCryptorAES256Settings
password:self.password
handler:^(RNCryptor *cryptor, NSData *data) {
@autoreleasepool {
[outputStream write:data.bytes maxLength:data.length];
dispatch_semaphore_signal(semaphore);

data = nil;
if (cryptor.isFinished) {
[outputStream close];
encryptionError = cryptor.error;
// call my delegate that I'm finished with decrypting
}
}
}];
while (inputStream.hasBytesAvailable) {
@autoreleasepool {
uint8_t buf[blockSize];
NSUInteger bytesRead = [inputStream read:buf maxLength:blockSize];
if (bytesRead > 0) {
NSData *data = [NSData dataWithBytes:buf length:bytesRead];

total = total + bytesRead;
[encryptor addData:data];

dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
}
}
}

[inputStream close];
[encryptor finish];
}

关于ios - 在 iOS 上使用 RNCryptor 加密/解密大文件时的内存问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15335803/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com