2011-12-01 87 views
0

我有一個UITableView,由大約10個名爲TBPostSnapCell的子類UITableViewCell組成。初始化時,每個單元格將其兩個變量設置爲UIImage,通過GCD下載或從存儲在用戶文檔目錄中的緩存中檢索。使用UITableView和GCD減少延遲

由於某些原因,這會在tableView上引起顯着的延遲,從而中斷應用程序&表的UX。

請你能告訴我如何減少這種滯後?

的tableView ...的cellForRowAtIndexPath:

if (post.postType == TBPostTypeSnap || post.snaps != nil) { 

     TBPostSnapCell *snapCell = (TBPostSnapCell *) [tableView dequeueReusableCellWithIdentifier:snapID]; 

     if (snapCell == nil) { 

      snapCell = [[[NSBundle mainBundle] loadNibNamed:@"TBPostSnapCell" owner:self options:nil] objectAtIndex:0]; 

      [snapCell setPost:[posts objectAtIndex:indexPath.row]]; 

      [snapCell.bottomImageView setImage:[UIImage imageNamed:[NSString stringWithFormat:@"%d", (indexPath.row % 6) +1]]]; 
     } 

    [snapCell.commentsButton setTag:indexPath.row]; 
    [snapCell.commentsButton addTarget:self action:@selector(comments:) forControlEvents:UIControlEventTouchDown]; 
    [snapCell setSelectionStyle:UITableViewCellSelectionStyleNone]; 

    return snapCell; 
} 

TBSnapCell.m

- (void) setPost:(TBPost *) _post { 

    if (post != _post) { 
     [post release]; 
     post = [_post retain]; 
    } 
    ... 

    if (self.snap == nil) { 

     NSString *str = [[_post snaps] objectForKey:TBImageOriginalURL]; 
     NSURL *url = [NSURL URLWithString:str]; 
     [TBImageDownloader downloadImageAtURL:url completion:^(UIImage *image) { 
      [self setSnap:image]; 
     }]; 
    } 

    if (self.authorAvatar == nil) { 
     ... 
     NSURL *url = [[[_post user] avatars] objectForKey:[[TBForrstr sharedForrstr] stringForPhotoSize:TBPhotoSizeSmall]]; 

     [TBImageDownloader downloadImageAtURL:url completion:^(UIImage *image) { 
      [self setAuthorAvatar:image]; 
     }]; 
     ... 
    } 

} 

TBImageDownloader.m

+ (void) downloadImageAtURL:(NSURL *)url completion:(TBImageDownloadCompletion)_block { 

    if ([self hasWrittenDataToFilePath:filePathForURL(url)]) { 
     [self imageForURL:filePathForURL(url) callback:^(UIImage * image) { 
      _block(image); //gets UIImage from NSDocumentsDirectory via GCD 
     }]; 
     return; 
    } 

    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0); 
    dispatch_async(queue, ^{ 
     UIImage *image = [UIImage imageWithData:[NSData dataWithContentsOfURL:url]]; 
     dispatch_async(dispatch_get_main_queue(), ^{ 
      [self writeImageData:UIImagePNGRepresentation(image) toFilePath:filePathForURL(url)]; 
      _block(image); 
     }); 
    }); 
} 

回答

2

首先要嘗試的轉換DISPATCH_QUEUE_PRIORITY_HIGH(又名ONG最重要的工作EVER FORGET EVERYTHEELSE)改爲像DISPATCH_QUEUE_PRIORITY_LOW之類的東西。

如果這樣不能解決問題,您可以嘗試通過dispatch_sources執行http流量,但這是很多工作。

你也許只是試圖限制帶有信號量的飛行中http提取的次數,真正的技巧將決定什麼是最佳限制,因爲「好」數量取決於網絡,CPU和內存壓力。也許基準2,4和8有一些配置,看看是否有足夠的模式來推廣。

好吧,讓我們嘗試只是一個,與更換queue = ...

static dispatch_once_t once; 
static dispatch_queue_t queue = NULL; 
dispatch_once(&once, ^{ 
    queue = dispatch_queue_create("com.blah.url-fetch", NULL); 
}); 

離開代碼的其餘部分不變。這可能是最小的諷刺,但可能不會非常快地加載圖像。

對於更一般的情況下,撕裂了我剛纔給你的變化,我們會在這方面努力:

dispatch_async(queue, ^{ 
    UIImage *image = [UIImage imageWithData:[NSData dataWithContentsOfURL:url]]; 
    dispatch_async(dispatch_get_main_queue(), ^{ 
     [self writeImageData:UIImagePNGRepresentation(image) toFilePath:filePathForURL(url)]; 
     _block(image); 
    }); 
}); 

與替換它:

static dispatch_once_t once; 
static const int max_in_flight = 2; // Also try 4, 8, and maybe some other numbers 
static dispatch_semaphore_t limit = NULL; 
dispatch_once(&once, ^{ 
    limit = dispatch_semaphore_create(max_in_flight); 
}); 
dispatch_async(queue, ^{ 
    dispatch_semaphore_wait(limit, DISPATCH_TIME_FOREVER); 
    UIImage *image = [UIImage imageWithData:[NSData dataWithContentsOfURL:url]]; 
    // (or you might want the dispatch_semaphore_signal here, and not below) 
    dispatch_async(dispatch_get_main_queue(), ^{ 
     [self writeImageData:UIImagePNGRepresentation(image) toFilePath:filePathForURL(url)]; 
     _block(image); 
     dispatch_semaphore_signal(limit); 
    }); 
}); 

注意:我的避風港沒有測試任何這些代碼,甚至看它是否編譯。正如所寫,它只會允許2個線程執行您的兩個嵌套塊中的大部分代碼。您可能需要將dispatch_semaphore_signal移至註釋行。這將限制你創建兩次抓取/圖像,但是它們將被允許與將圖像數據寫入文件並調用_block回調重疊。

順便說一句,你做了很多的文件I/O,這是閃存更快,然後任何磁盤曾經是,但如果你仍然在尋找可能是另一個地方攻擊性能的勝利。例如,可能需要將UIImage保存在內存中,直到獲得低內存警告,然後纔將它們寫入磁盤。

+0

謝謝,我已經嘗試將優先級設置爲低,並且似乎略微減少了滯後。你能舉一個使用信號量的例子嗎? –

+0

提供的示例。祝你好運。 – Stripes

+0

感謝您提供示例代碼,表格現在運行時滯後時間相當長!還有一些滯後,但我認爲這是關於一些石英核心繪圖。 –