アプリの安定化に関するアドバイスを探しています。まず、いくつかの要件-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にアクセスしようとしている2つのスレッドが存在する可能性があると思われます
(MyCell *cell = (MyCell*)[tableView dequeueReusableCellWithIdentifier:CellTableIdentifier];)
常にすぐに発生するわけではありませんが、最終的に、セルのtableViewリストをスクロールすると、アプリが次のようにクラッシュします。*キャッチされない例外'NSGenericException'が原因でアプリを終了します。列挙された。」
セルに復号化された画像を含める必要があります。最初の解決策(上記)では、画像が利用可能になったときにこれを実行しますが、アプリがクラッシュします。すべてのスレッドを開始して取得および復号化する前に、画像を復号化してloadAndShowThumbnailImageでそのキャッシュをチェックしたときに、ある種のメモリ内キャッシュがこれを改善するのに役立つかどうか疑問に思っています。
考え?私はこれを1週間強打してきましたが、今ではさまざまなことを試しています。新鮮な視点をいただければ幸いです。
ありがとう。