问题
I am using AFNetworking to download files from my server. It works fine. But I have one issue: My ProgressView updates wrong cell(UI, not data) when I scroll up or down. Here is my code:
My Cell:
AFHTTPRequestOperation *operation;
@property (weak, nonatomic) IBOutlet DACircularProgressView *daProgressView;
- (IBAction)pressDown:(id)sender {
AFAPIEngineer *apiEngineer = [[AFAPIEngineer alloc] initWithBaseURL:[NSURL URLWithString:AF_API_HOST]];
operation = [apiEngineer downloadFile:(CustomObject*)object withCompleteBlock:^(id result) {
} errorBlock:^(NSError *error) {
}];
__weak typeof(self) weakSelf = self;
apiEngineer.afProgressBlock = ^(double progress, double byteRead, double totalByToRead) {
[weakSelf.daProgressView setProgress:progress animated:YES];
};
}
- (void)setDataForCell:(id)object{
}
My table:
- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
CustomCell *cell = (CustomCell*)[tableView dequeueReusableCellWithIdentifier:NSStringFromClass([CustomCell class])];
cell.backgroundColor = [UIColor clearColor];
CustomObject *aObject = [listObject objectAtIndex:indexPath.row];
[cell setDataForCell: aObject];
return cell;
}
My downloadHelper:
- (AFDownloadRequestOperation*)downloadFile:(CustomObject*)aObject
withCompleteBlock:(AFResultCompleteBlock)completeBlock
errorBlock:(AFResultErrorBlock)errorBlock{
NSString *link = URL;
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:link]];
NSString *path = [NSString databasePathWithPathComponent:[NSString stringWithFormat:@"%@.zip", @"noname"]];
AFDownloadRequestOperation *operation = [[AFDownloadRequestOperation alloc] initWithRequest:request targetPath:path shouldResume:YES];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
completeBlock(responseObject);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
errorBlock(error);
}];
[operation setProgressiveDownloadProgressBlock:^(AFDownloadRequestOperation *operation, NSInteger bytesRead, long long totalBytesRead, long long totalBytesExpected, long long totalBytesReadForFile, long long totalBytesExpectedToReadForFile) {
float progressF = (float)totalBytesReadForFile / totalBytesExpectedToReadForFile;
self.afProgressBlock(progressF, totalBytesReadForFile, totalBytesExpectedToReadForFile);
}];
[operation start];
return operation;
}
When I press button 'Download' in first cell:
When I scroll down then scroll up, It is second cell:
So, my question is: How to update UIProgressView on UITableViewCell? What is wrong with my code?
回答1:
Because cells are re-used, you simply can't just keep a weak reference to the cell and update the cell's progress view. At the very least, rather than using a weak reference to the table view cell, you would use the index path, look up the correct cell using [tableView cellForRowAtIndexPath:indexPath]
(this is a UITableView
method that identifies the cell associated with a particular NSIndexPath
and should not to be confused with the similarly named UITableViewDataSource
method in which we do our cell dequeueing/configuring logic), and update that cell's progress view (assuming that cell is even visible).
Frankly, even that is dangerous, as it assumes that it's impossible to add or remove cells while downloads are in progress. (And that is obviously not a reasonable assumption/constraint to place upon an app.) Quite frankly, every time one wants to update download progress, one really should go back to the model, lookup the correct NSIndexPath
based for the model object in question, and then use the above cellForRowAtIndexPath
pattern to find and then update the cell in question.
Note, that suggests that the initiation of the download request may not be initiated by the table view cell. Personally, I maintain a model object that consists of an array of files to download, and associate the download queue with that, rather than the cell (though the progress handler would obviously update the cell). In short, you want a loosely coupled relationship between the UI (e.g. the cell) and the model driving the downloads.
Note, many naive implementations consider all of the above points and decide to abandon cell reuse in order to simplify the problem. I won't belabor the point, but I think that's a fundamentally misguided approach. In my opinion, one should have a proper model for the downloads separate from the view objects.
回答2:
I have a small project on github that basically does what you want with a different style progress indicator. I built it a while back and it uses exactly the approach Rob mentions: The table and its cells are backed by a "model" that tells cells at a given index
what their state should be. I also make sure cells are reused. It may be of some use to you:
https://github.com/chefnobody/StreamingDownloadTest
来源:https://stackoverflow.com/questions/29202212/uiprogressview-on-uitableviewcell