寻找有关稳定我的应用程序的一些建议。首先是一些要求 - 带有PII(个人识别信息)的文件必须在磁盘上加密。 Tumbnails和徽标位于自定义TableViewCells(如果可用)中,必须在显示之前解密。
有几层线程正在进行中。有一个中央函数getFileData,用于检查文件是否在设备上,或者是否需要从网络获取文件。我希望保持用户界面的响应能力,而且(我认为)这就是我的问题。
以下是一些代码: 这是在我的应用程序中处理文件的主力方法。它决定文件解密的位置并将其交回回调:
-(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'终止应用程序,原因:'* 集合< __ NSCFSet:0xde6a650>在被列举时被突变。'
我需要在单元格中包含解密图像,并且第一个解决方案(上面)在图像可用时为我执行此操作但导致应用程序崩溃。我想知道是否某种内存缓存有助于改善这一点,如果我在解密时将图像放入内存中并在启动所有线程以获取和解密之前检查缓存在loadAndShowThumbnailImage中。
思考?我已经敲了一个星期,现在尝试不同的东西,并会欣赏一些新观点。
感谢。
答案 0 :(得分:0)
基于Justins链接和后续研究,我最终走向了这个方向:In a UITableView, best method to cancel GCD operations for cells that have gone off screen?