2012-11-29 33 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]; 
} 

非常感谢大家的帮助。