It's important to realize that your progress bars will not be shown all the time (i.e. the user can scroll the table, and once offscreen that same cell can be reused at another index position for different content). So what you will need to do is have somewhere you can store the data about any active downloads, including the index position in the table, the total file size, and the number of bytes downloaded so far. Then, whenever your cell is drawn, you'll need to check whether the item for that cell is currently being downloaded and if so, show the bar with the appropriate percentage progress.
The easiest way to do this would be to add a property to your view controller to store this info. It can be an NSMutablerray
that will hold a collection of NSMutableDictionary
objects, each dictionary will contain the necessary info about an active download.
@property (nonatomic, strong) NSMutableArray *activeConnections;
First you'll initialize the array in viewDidLoad:
:
- (void)viewDidLoad
{
[super viewDidLoad];
//...
self.activeConnections = [[NSMutableArray alloc] init];
}
Whenever a button is pressed, you'll add an NSMutableDictionary object to your array with the info you'll need.
- (void)downloadFileWhenPressedButton:(UIButton*)sender
{
// ...
// then create dictionary
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
[dict setObject:con forKey:@"connection"]; // save connection so we can reference later
[dict setObject:[NSNumber numberWithInt:[sender.tag]/10] forKey:@"row"]; // this is the row index from your table
[dict setObject:[NSNumber numberWithInt:999] forKey:@"totalFileSize"]; // dummy size, we will update when we know more
[dict setObject:[NSNumber numberWithInt:0] forKey:@"receivedBytes"];
[self.activeConnections addObject:dict];
}
Also we'll create two utility methods so we can find easily retrieve the connection info from our array, using either the connection object itself, or the row index position in the table.
- (NSDictionary*)getConnectionInfo:(NSURLConnection*)connection
{
for (NSDictionary *dict in self.activeConnections) {
if ([dict objectForKey:@"connection"] == connection) {
return dict;
}
}
return nil;
}
- (NSDictionary*)getConnectionInfoForRow:(int)row
{
for (NSDictionary *dict in self.activeConnections) {
if ([[dict objectForKey:@"row"] intValue] == row) {
return dict;
}
}
return nil;
}
When the connection is established, update your dictionary with the expected length
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
// ...
NSDictionary *dict = [self getConnectionInfo:connection];
[dict setObject:[NSNumber numberWithInt:response.expectedContentLength] forKey:@"totalFileSize"];
}
As you receive data, you'll update the number of received bytes and tell your tableView to redraw the cell containing the progress bar.
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
// ...
NSDictionary *dict = [self getConnectionInfo:connection];
NSNumber bytes = [data length] + [[dict objectForKey:@"receivedBytes"] intValue];
[dict setObject:[NSNumber numberWithInt:response.expectedContentLength] forKey:@"receivedBytes"];
int row = [[dict objectForKey:@"row"] intValue];
NSIndexPath *indexPath = [NSIndexPathindexPathForRow:row inSection:0];
[self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
withRowAnimation:UITableViewRowAnimationNone];
}
When your connection is done downloading, you should remove the connection from your activeConnections array, and reload the table cell.
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
// ...
NSDictionary *dict = [self getConnectionInfo:connection];
[self.activeConnections removeObject:dict];
int row = [[dict objectForKey:@"row"] intValue];
NSIndexPath *indexPath = [NSIndexPathindexPathForRow:row inSection:0];
[self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
withRowAnimation:UITableViewRowAnimationNone];
}
Finally, in cellForRowAtIndexPath:
you'll need to draw the cell's progress bar based on the info in your activeConnections array.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// ...
// remove any previous buttons or progress bars from this cell
for (UIView *view in [cell.contentView subViews]) {
if ([view isKindOfClass:[UIProgressView class]] || [view isKindOfClass:[UIButton class]]) {
[view removeFromSuperView];
}
}
// look for active connecton for this cell
NSDictionary *dict = [self getConnectionInfoForRow:indexPath.row];
if (dict) {
// there is an active download for this cell, show a progress bar
UIProgressView *dlProgress = [[UIProgressView alloc] initWithProgressViewStyle:UIProgressViewStyleDefault];
dlProgress.frame = CGRectMake(cell.frame.size.width-150, 17, 50, 9);
dlProgress.tag = indexPath.row*10+1;
dlProgress.progress = [[dict objectForKey:@"receivedBytes"] intValue] / [[dict objectForKey:@"totalFileSize"] intValue];
[cell.contentView addSubview:dlProgress];
} else {
// no active download, show the download button
UIButton *dl = [UIButton buttonWithType:UIButtonTypeCustom];
dl.tag = indexPath.row*10;
[dl setBackgroundImage:[UIImage imageNamed:@"downloadButton.png"] forState:UIControlStateNormal];
[dl setBackgroundImage:[UIImage imageNamed:@"downloadButtonH.png"] forState:UIControlStateHighlighted];
[dl setFrame:CGRectMake(230.0, (cell.frame.size.height-28)/2, 28, 28)];
[dl addTarget:self action:@selector(downloadFileWhenPressedButton:) forControlEvents:UIControlEventTouchUpInside];
[cell.contentView addSubview:dl];
}
}