6

I am trying to update a each table cell with progress bar loading, but I am stuck. I created a custom cell for a table view with these properties:

@interface OFPTableCell : UITableViewCell 
@property (nonatomic, weak) IBOutlet UILabel *textLabel;
@property (nonatomic, weak) IBOutlet UILabel *detailTextLabel;
@property (weak, nonatomic) IBOutlet UIImageView *imageView;
@property (weak, nonatomic) IBOutlet UIProgressView *progressView;
@end;

and after just @synthesize them, now i have in each table cell a progress bar as expected.

The problem is that when i try to update even 1 st cell with a loading progress bar it just do nothing or its set 0 or full progress bar. Note that the download process is working fine.

Bellow you may find the code where i try to update the progress bar:

 - (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask          *)downloadTask didWriteData:(int64_t)bytesWritten
  totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:    (int64_t)totalBytesExpectedToWrite
{

      dispatch_async(dispatch_get_main_queue(), ^{
      NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:0];
      OFPTableCell *cell = (OFPTableCell*)[self tableView:self.tableViewCache    cellForRowAtIndexPath:indexPath];
      cell.progressView.progress=(double)totalBytesWritten /  (double)totalBytesExpectedToWrite;
});

}

Below is the method cellForRowAtIndexPath :

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{

     OFPTableCell *cell = [self.tableViewCache dequeueReusableCellWithIdentifier:@"Cell"];



    OFPVideoDetails *vd = [someArray objectAtIndex:indexPath.row];
    cell.textLabel.text=vd1;
    cell.detailTextLabel.text=vd2;

    CGSize size = {65,53};
    cell.imageView.image =[self imageWithImage:[UIImage       imageWithContentsOfFile:vd.imageUrl] scaledToSize:size];



     cell.delegate = self;



 return cell;
 } 
Ben Scheirman
  • 40,531
  • 21
  • 102
  • 137
user3197376
  • 63
  • 1
  • 1
  • 4

3 Answers3

8

It's very bad practise to call method tableView:cellForRowAtIndexPath:directly, becuase the cell may not exist at the same moment and it may be a cause of the bug you have.

Basically you should do this in another way: add an array of double:

double progressValues[30]; // 30 is the count of rows on your tableView, you can set the size dynamically

and use it like this:

- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten 
totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:
(int64_t)totalBytesExpectedToWrite
{
  dispatch_async(dispatch_get_main_queue(), ^{
  NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:0];
  OFPTableCell *cell = (OFPTableCell*)[self tableView:self.tableViewCache    cellForRowAtIndexPath:indexPath];
  progressValues[indexPath.row] = (double)totalBytesWritten /  (double)totalBytesExpectedToWrite;
  [self.tableViewCache reloadData];
});
}

and in the dataSource method just add this string:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    //... your code...
    cell.progressView.progress = progressValues[indexPath.row];
    // ...
    return cell;
}
Miroslav
  • 546
  • 2
  • 9
  • 22
  • 2
    One more question instead of [self.tableViewCache reloadData]; i can use [self.tableViewCache reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationNone]; ? – user3197376 Jan 15 '14 at 10:54
  • Yes, of course you'd better reload only one row, which changes at the current time. I wrote above just general idea without taking into account such details :) – Miroslav Jan 15 '14 at 10:59
  • I'm getting **nil** in: **cell.progressView.progress = progressValues[indexPath.row];** – Mohammad Zaid Pathan Feb 04 '15 at 07:26
  • 1
    but how to identify for which cell we are showing progressview ? – Darshan May 04 '16 at 05:11
1

You should keep the value of (double)totalBytesWritten / (double)totalBytesExpectedToWrite in OFPVideoDetails (add one property "progress" in OFPVideoDetails).

Then reload the cell in - (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite: (int64_t)totalBytesExpectedToWrite

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    OFPTableCell *cell = [self.tableViewCache dequeueReusableCellWithIdentifier:@"Cell"];
    OFPVideoDetails *vd = [someArray objectAtIndex:indexPath.row];
    cell.textLabel.text=vd1;
    cell.detailTextLabel.text=vd2;
    CGSize size = {65,53};
    cell.imageView.image =[self imageWithImage:[UIImage       imageWithContentsOfFile:vd.imageUrl] scaledToSize:size];
    cell.progressView.progress = vd.progress;
    cell.delegate = self;
    return cell;
}
KudoCC
  • 6,912
  • 1
  • 24
  • 53
0

For Swift 4.2

  func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) {

          DispatchQueue.main.async(execute: {
            let indexPath = IndexPath(row: 0, section: 0)
            let cell = self.tableView(self.tableViewCache, cellForRowAt: indexPath) as? OFPTableCell
            progressValues[indexPath.row] = Double(totalBytesWritten) / Double(totalBytesExpectedToWrite)
            self.tableViewCache.reloadData()
        })
    }
Kavin Soni
  • 101
  • 1
  • 3