[英]UIProgressView indicator not updating with the correct “progress”
我正在異步下載圖像並在UITableView中顯示它們。 下載圖像時,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方法中添加了一個nil檢查:
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;
我想你每次調用委托方法時都會通過重新加載表格單元來采取錯誤的方法。 您可以直接獲取可見單元格並直接更新進度指示器,而不是通過數據源。
我假設你有一些方法可以將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)];
}
}
}
但是,您應該知道,如果您有比可見單元格更多的下載,則此解決方案是不夠的 - 您還應該在數據源中的某處存儲每個下載的進度,以便在表格視圖需要重新加載時單元格(由於滾動),它知道如何設置進度指示器。
在很多情況下我發現你認為你擁有的單元格不是那個正在更新的單元格。 當你重新加載時,你的代碼會彈出可重用的單元格,這基本上是一個舊單元格。 如果重新加載,該單元格將被另一個單元格替換。 (如果可重用的單元格返回nil,你還沒有包括分配新的單元格。如果你的單元格滾動,它會被重新加載,所以你必須確保你將進度條放在那里的單元格上,而不是曾經在那里的人。 您可能希望NSLog使用您開始傳輸的單元格的地址,然后每次更新進度時再次。 您需要使用該索引路徑上的當前單元格更新進度條。 它可能不是您最初啟動該過程的那個。
回到這個差不多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];
}
非常感謝大家的幫助。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.