线程正在杀死我的应用程序

时间:2012-09-01 01:29:57

标签: objective-c ios

寻找有关稳定我的应用程序的一些建议。首先是一些要求 - 带有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中。

思考?我已经敲了一个星期,现在尝试不同的东西,并会欣赏一些新观点。

感谢。

1 个答案:

答案 0 :(得分:0)

基于Justins链接和后续研究,我最终走向了这个方向:In a UITableView, best method to cancel GCD operations for cells that have gone off screen?