尋求關於穩定我的應用程序的一些建議。首先一些要求 - 帶有PII(個人識別信息)的文件必須在磁盤上加密。 Tumbnails和徽標位於自定義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'而終止應用程序,原因:'*收集< __NSCFSet:0xde6a650>在枚舉時發生了變化。
我需要在單元格中具有解密的圖像,並且當圖像可用但第一個解決方案(上圖)會爲應用程序崩潰時執行此操作。我想知道是否某種內存緩存可以幫助改善這種情況,如果我在解密時將圖像放在內存中,並在啓動所有線程以獲取和解密它們之前檢查loadAndShowThumbnailImage中的緩存。
想法?我一直在爲此嘗試了不同的事情,並感謝一些新的觀點。
謝謝。
由於有消息稱,你不能突變的集合(或陣列/字典),而它的被枚舉......這可發生在後臺線程正在改變前臺線程正在迭代的集合時。你能否將相關數據結構的副本傳遞給後臺線程? – nielsbot
後臺線程只能在NSData對象上工作(除非在我使用的[link] https://github.com/rnapier/RNCryptor庫中還有別的事情發生,我還沒有看到它太深,只是足以確保它對我的需求來說確實足夠安全我在想,枚舉的數組/字典在主線程中,並且唯一要迭代的對象是託管對象的一個屬性,我稱其爲File: @property(nonatomic,retain)NSSet *郵件; – hippeelee
必須有一個共享設置才能彈出這個錯誤,我自己打這個,深入挖掘一下,看看能不能找到共享對象 – nielsbot