2012-11-29 36 views
1

我正在異步下載圖像並在UITableView中顯示它們。在下載圖像時,應在相應的表格行中顯示UIProgressView。下載完成後,進度視圖應由實際圖像替換。UIProgressView指示符未用正確的「進度」更新

在我的表格視圖中,我使用了一個名爲ProgressTableViewCell的自定義單元,它從UITableViewCell分類。它有一個UIProgressView IBOutlet。

我從NSURLConnection創建了一個NSOperation,並將它們添加到NSOperationQueue中。作爲代表的

didReceiveData

方法被調用,通知被貼到我的表視圖控制器

reloadRowsAtIndexPaths

表視圖的方法來更新相應的錶行。我的cellForRowAtIndexPath做爲重載行以下:

ProgressTableViewCell *cell = (ProgressTableViewCell*)[tableView dequeueReusableCellWithIdentifier:@"ProgressCell"]; 

    float received = [[downloadInfo objectForKey:@"receivedBytes"] floatValue]; 
    float total = [[downloadInfo objectForKey:@"totalFileSize"] floatValue]; 

    NSNumber* percentage= [NSNumber numberWithFloat:received/total]; 
    NSMutableDictionary* userInfo = [[NSMutableDictionary alloc] init]; 
    NSLog(@"percentage %f", percentage.floatValue); 
    [userInfo setObject:cell forKey:@"cell"]; 
    [userInfo setObject:percentage forKey:@"percentage"]; 

    [self performSelectorOnMainThread:@selector(updateProgressView:) withObject:userInfo waitUntilDone:NO]; 
    NSLog(@"received: %@", [downloadInfo objectForKey:@"receivedBytes"]); 

    NSLog(@"Progress: %f", cell.progressView.progress); 
    return cell; 

的updateProgressView方法看起來像

- (void)updateProgressView :(NSMutableDictionary *)userInfo 
{ 
    ProgressTableViewCell* cell = [userInfo valueForKey:@"cell"]; 

    NSNumber* progress = [userInfo valueForKey:@"percentage"]; 

    [cell.progressView setProgress:progress.floatValue ]; 
    NSLog(@"Progress after update: %f", cell.progressView.progress); 
} 

我更新在主線程的進展看法,我甚至試圖waitUntilDone設置爲YES,但到徒勞無功。我的進展觀保持在零點。偶爾當我調試時,我可以看到進度指示器中的一些變化,這使得我認爲這可能是一個計時問題。但如何解決它?

編輯:這裏是NSURLConnection的委託的didReceiveData方法:

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data { 
    [_responseData appendData:data]; 
    NSNumber* bytes = [NSNumber numberWithUnsignedInt:[data length]]; 

    NSLog(@"received bytes:%d", [bytes intValue]); 
    NSMutableDictionary* userInfo = [[NSMutableDictionary alloc] init]; 
    [userInfo setObject:_responseId forKey:@"responseId"]; 
    [userInfo setObject:bytes forKey:@"receivedBytes"]; 

    [self fireNotification: [NSNotification 
            notificationWithName:@"DidReceiveData" 
            object:self userInfo:userInfo]]; 
} 



- (void)fireNotification :(NSNotification *)aNotification 
{ 
    [[NSNotificationCenter defaultCenter] postNotification:aNotification]; 
} 

這裏是我的視圖控制器的方法得到通知:

-(void) dataReceived:(NSNotification *)notification { 

    NSNumber* responseId = [[notification userInfo] objectForKey:@"responseId"]; 
    NSNumber* bytes = [[notification userInfo] objectForKey:@"receivedBytes"]; 

    NSMutableDictionary* downloadInfo = [self getConnectionInfoForId:responseId]; 

    NSLog(@"received bytes:%ld for response %@", [bytes longValue], responseId); 
    NSNumber* totalBytes = [NSNumber numberWithInt:([bytes longValue] + [[downloadInfo objectForKey:@"receivedBytes"] longValue]) ]; 
    [downloadInfo setObject:totalBytes forKey:@"receivedBytes"]; 

    float received = [[downloadInfo objectForKey:@"receivedBytes"] floatValue]; 
    float total = [[downloadInfo objectForKey:@"totalFileSize"] floatValue]; 

    [downloadInfo setObject:[NSNumber numberWithFloat:received/total] forKey:@"progress"]; 

    [self reloadRowForResponse:responseId]; 

} 

我還添加了一個零檢查,我的cellForRowAtIndexPath方法建議如下:

ProgressTableViewCell *cell = (ProgressTableViewCell*)[tableView dequeueReusableCellWithIdentifier:@"ProgressCell"]; 
    if (cell == nil) 
    { 
     NSArray *nib = [[NSBundle mainBundle] loadNibNamed:@"ProgressCell" owner:self options:nil]; 
     cell = [nib objectAtIndex:0]; 
    } 
    float received = [[downloadInfo objectForKey:@"receivedBytes"] floatValue]; 
    float total = [[downloadInfo objectForKey:@"totalFileSize"] floatValue]; 

    NSNumber* percentage= [NSNumber numberWithFloat:received/total]; 
    NSMutableDictionary* userInfo = [[NSMutableDictionary alloc] init]; 
    NSLog(@"cell:%@", cell); 
    NSLog(@"percentage %f", percentage.floatValue); 
    [userInfo setObject:cell forKey:@"cell"]; 
    [userInfo setObject:percentage forKey:@"percentage"]; 

    [self performSelectorOnMainThread:@selector(updateProgressView:) withObject:userInfo waitUntilDone:NO]; 

    return cell; 
+0

你可以發佈你的委託方法和你用來處理通知的方法嗎?我的猜測是,如果你有通知處理程序中的索引路徑和下載信息,你應該在那裏更新進度視圖,而不是每次重新載入表視圖。 –

+0

我已經發布了這些方法喬。你可以在EDIT下面看到它們。事情是我有一個正在下載的每個圖像的進度視圖,這就是爲什麼我在表視圖的數據源委託方法中進行更新。 – ganime

回答

0

我在很多情況下發現l這就是說你認爲你擁有的細胞不是那個正在更新的細胞。當你重新加載時,你的代碼會從可重用的區域彈出一個單元格,這基本上是一箇舊單元格。如果你重新加載,那個單元被另一個替換。 (如果可重用的單元格返回nil,您也沒有包括分配新單元格)如果您的單元格滾動,它將被重新加載,所以您必須確保您將進度條放在那裏的單元格上,而不是一個曾經在那裏的人。您可能需要NSLog記錄您開始傳輸的單元格的地址,然後每次更新進度時再次登錄。您需要使用該索引路徑上的當前單元更新進度欄。它可能不是您最初開始處理的那個人。

+0

確實是歐文。當我NSLog單元格地址時,我每次都得到一個不同的地址。但爲什麼即使重複使用單元格也會發生這種情況?另外,當我只有一個圖像下載時,它是如何更新不同的progres視圖的。我怎樣才能「確保我將進度條放在那裏的單元格上,而不是曾經在那裏的單元格上」。 ? – ganime

+1

當你重複使用單元時,這就是你正在做的事情。滾動時,曾經位於第零行的單元格將在第12行中重複使用。因此,用於啓動下載的單元對象不在同一個地方。我使用自定義單元格對象,以便可以確定哪個單元格具有我的下載對象,並通過它們進行搜索以找到它。另請注意,您的下載單元格可能會滾動到屏幕外。重要的是,當您加載/重新使用新的單元格時,您可以更新任何文件下載的參考。 –

3

我想你每次調用委託方法時都會通過重新加載表格單元來採取錯誤的做法。您可以直接抓取可見單元格並直接更新進度指示符,而不是通過數據源。

我假設你有一些方法可以將responseId轉換爲你想要更新的那一行的索引路徑 - 假設在你的控制器中叫做indexPathForResponseID:。而不是重新裝入電池,你可以抓住電池,如果是可見的,並更新其進度指示器:

- (void)dataReceived:(NSNotification *)notification { 

    ... 

    float received = [[downloadInfo objectForKey:@"receivedBytes"] floatValue]; 
    float total = [[downloadInfo objectForKey:@"totalFileSize"] floatValue]; 

    NSIndexPath *cellPath = [self indexPathForResponseID:responseId]; 
    ProgressTableViewCell *cell = (ProgressTableviewCell *)[self.tableView cellForRowAtIndexPath:cellPath]; 
    if (cell) { 
     // make sure you're on the main thread to update UI 
     dispatch_async(dispatch_get_main_queue(), ^{ 
      [cell.progressView setProgress: (received/total)]; 
     } 
    } 
} 

你應該知道,不過,如果你有比可見光的細胞更多下載該解決方案是不夠的 - 您還應該將每次下載的進度存儲在數據源的某處,以便如果表視圖需要重新加載單元格(由於滾動),它知道如何設置進度指示器。

+0

終於找到了解決方案(請參閱我自己的答案)。但我今天嘗試了你的建議,似乎有效。不記得爲什麼我2個月前無法使用它。我以另一種方式去做,因爲你提到的原因,我將不得不做更多的工作。不管怎麼說,還是要謝謝你。 – ganime

0

大概2個月後回來,我似乎找到了解決辦法。不知道這是否是好的做法,但每次更新進度時創建一個新的UIProgressView似乎解決了我的問題。這裏是方法:

-(void)updateProgressView :(NSMutableDictionary *)userInfo 
{ 
    ProgressTableViewCell* cell = [userInfo objectForKey:@"cell"]; 
    cell.backgroundColor =[UIColor darkGrayColor]; 
    NSNumber* progress = [userInfo objectForKey:@"percentage"]; 
    NSLog(@"Progress before update: %f", cell.progressView.progress); 

    UIProgressView *pView = [[UIProgressView alloc] initWithProgressViewStyle:UIProgressViewStyleDefault]; 
    pView.frame = CGRectMake(150, 200, 150, 9); 
    pView.progress = progress.floatValue; 

    [cell.contentView addSubview:pView]; 
} 

非常感謝大家的幫助。