寻找一些关于稳定我的应用程序的建议。首先是一些要求 - 带有 PII(个人识别信息)的文件在磁盘上时必须加密。缩略图和徽标位于自定义 TableViewCells(如果可用)中,必须在显示前解密。
有几层线程正在进行。有一个中央函数 getFileData 用于检查文件是否在设备上,或者是否需要从网络获取文件。我希望保持 UI 响应,并且(我认为)这就是我的问题。
这是一些代码: 这是在我的应用程序中处理文件的主要方法。它决定文件在哪里解密并将其交还给回调:
-(void)fetchFileData:(UserSession *) session
onComplete: (void(^)(NSData* data)) onComplete
{
NSURL *url = [File urlForMail:self.fileId andSession:session];
//NSLog(@"File id: %@", self.fileId);
NSString *encryptionKey = session.encryptionKey;
dispatch_queue_t cryptoQ = dispatch_queue_create(FILE_CRYPTOGRAPHY_QUEUE, NULL);
dispatch_async(cryptoQ, ^(void){
// Get the file and d/encrypt it
NSError *error = nil;
if ([File fileExistsAtUrl:url] == YES) {
NSLog(@"file is on disk.");
NSData *localEncryptedFile = [File getDataForFile:url];
NSData *decryptedFile = [RNDecryptor decryptData:localEncryptedFile
withPassword:encryptionKey
error:&error];
onComplete(decryptedFile);
dispatch_release(cryptoQ);
} else {
//NSLog(@"File is not on disk");
NSDictionary *remoteFile = [session.apiFetcher getFileContent:self.fileId
andToken:session.token];
if (remoteFile && [[remoteFile objectForKey:@"success"] isEqualToString:@"true"]) {
NSData *remoteFileData = [remoteFile objectForKey:@"data"];
NSString *mimeType = [remoteFile objectForKey:@"mimeType"];
self.mimeType = mimeType;
NSData *encryptedData = [RNEncryptor encryptData:remoteFileData
withSettings:kRNCryptorAES256Settings
password:encryptionKey
error:&error];
[encryptedData writeToURL:url atomically:YES];
onComplete(remoteFileData);
dispatch_release(cryptoQ);
}
}
});
下面是一个 getFileData 调用者的例子:
+(void)loadThumbnailForMail: (NSNumber*)thumbnailId
session: (UserSession*)session
callback: (void(^)(NSData* data))callback
{
File *file = [File findFile:thumbnailId inContext:session.mailDatabase.managedObjectContext];
dispatch_queue_t fetchQ = dispatch_queue_create(FILE_FETCHER_QUEUE_LABEL, NULL);
dispatch_async(fetchQ, ^(void) {
if (file) {
[file fetchFileData:session onComplete:^(NSData *data) {
if (data && file.mimeType) {
callback(data);
}
}];
}
});
dispatch_release(fetchQ);
}
下面是调用 loadThumbnailForMail 的 TableViewCell 示例:
-(void)loadAndShowThumbnailImage:(Mail*) mail
{
UIImage *placeHolder = [UIImage imageNamed:@"thumbnail_placeholder.png"];
[self.thumbnailImageForMail setImage:placeHolder];
dispatch_queue_t loaderQ = dispatch_queue_create(THUMBNAIL_FETCHER, NULL);
dispatch_async(loaderQ, ^ {
[File loadThumbnailForMail: mail.thumbnailId
session: [UserSession instance]
callback: ^(NSData *data) {
dispatch_async(dispatch_get_main_queue(), ^{
UIImage *thumbnailImage = [UIImage imageWithData:data];
[self.thumbnailImageForMail setImage:thumbnailImage];
});
}];
});
dispatch_release(loaderQ);
}
我认为我的问题是我的 loadThumbnailImage 中的回调。如果用户滚动得足够快,我怀疑可能有两个线程试图访问同一个 TableViewCell
(MyCell *cell = (MyCell*)[tableView dequeueReusableCellWithIdentifier:CellTableIdentifier];)
它并不总是立即发生,但最终,在滚动单元格的 tableView 列表后,应用程序崩溃:* 由于未捕获的异常 'NSGenericException' 导致应用程序崩溃,原因:'* Collection <__NSCFSet: 0xde6a650> 在被更改时发生了突变枚举。
我需要在单元格中保存解密的图像,当图像可用但导致应用程序崩溃时,第一个解决方案(上面)为我执行此操作。我想知道如果我在解密图像时将图像放在内存中并在我启动所有线程以获取和解密它们之前检查 loadAndShowThumbnailImage 中的缓存,那么某种内存缓存是否有助于改善这一点。
想法?我已经为此努力了一周,现在尝试不同的事情,并希望能有一些新的视角。
谢谢。