dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){
NSURL *url = [NSURL URLWithString: detailedActivity.pictures];
NSData *data = [[NSData alloc] initWithContentsOfURL:url];
dispatch_async(dispatch_get_main_queue(), ^(void){
self.activityImageView.image = [[UIImage alloc]initWithData:data];
});
});
本文转载至 http://stackoverflow.com/questions/16663618/async-image-loading-from-url-inside-a-uitableview-cell-image-changes-to-wrong
favorite
34 |
I’ve written two ways to async load pictures inside my UITableView cell. In both cases the image will load fine but when I’ll scroll the table the images will change a few times until the scroll will end and the image will go back to the right image. I have no idea why this is happening.
#define kBgQueue dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)- (void)viewDidLoad { [super viewDidLoad]; dispatch_async(kBgQueue, ^{ NSData* data = [NSData dataWithContentsOfURL: [NSURL URLWithString: @"http://myurl.com/getMovies.php"]]; [self performSelectorOnMainThread:@selector(fetchedData:) withObject:data waitUntilDone:YES]; }); }-(void)fetchedData:(NSData *)data { NSError* error; myJson = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error]; [_myTableView reloadData]; } - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { // Return the number of sections. return 1; }- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{ // Return the number of rows in the section. // Usually the number of items in your array (the one that holds your list) NSLog(@"myJson count: %d",[myJson count]); return [myJson count]; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{ myCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell"]; if (cell == nil) { cell = [[myCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"cell"]; } dispatch_async(kBgQueue, ^{ NSData *imgData = [NSData dataWithContentsOfURL:[NSURL URLWithString:[NSString stringWithFormat:@"http://myurl.com/%@.jpg",[[myJson objectAtIndex:indexPath.row] objectForKey:@"movieId"]]]]; dispatch_async(dispatch_get_main_queue(), ^{ cell.poster.image = [UIImage imageWithData:imgData]; }); }); return cell; }
… …
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{ myCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell"]; if (cell == nil) { cell = [[myCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"cell"]; } NSURL* url = [NSURL URLWithString:[NSString stringWithFormat:@"http://myurl.com/%@.jpg",[[myJson objectAtIndex:indexPath.row] objectForKey:@"movieId"]]]; NSURLRequest* request = [NSURLRequest requestWithURL:url]; [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse * response, NSData * data, NSError * error) { if (!error){ cell.poster.image = [UIImage imageWithData:data]; // do whatever you want with image } }]; return cell; }
ios objective-c cocoa-touch uitableview
|
|
|
You’re trying to store information in the actual cells. This is bad, very bad. You should store information in n array (or something similar) and then display it in the cells. The information in this case is the actual UIImage. Yes load it asynchronously but load it into an array. – Fogmeister May 21 ’13 at 7:00 |
|
@Fogmeister Are you referring to poster ? That’s presumably an imageview in his custom cell, so what EXEC_BAD_ACCESS is doing is perfectly right. You are correct that you should not use the cell as the repository for model data, but I don’t think that’s what he’s doing. He’s just giving the custom cell what it needs to present itself. Furthermore, and this is a more subtle issue, I would be wary about storing an image, itself, in your model array backing your tableview. It’s better to use a image caching mechanism and your model object should retrieve from that cache. – Rob May 21 ’13 at 14:23 |
|
Yes, exactly my point. Looking at the request (which is shown in full) he is downloading the image asynchronously and putting it directly into the imageView in the cell. (Thus using the cell to store the data, i.e. the image). What he should be doing is referencing an object and requesting the image from that object (contained in an array or somewhere). If the object doesn’t yet have the image it should return a placeholder and download the image. Then when the image is downloaded and ready to display let the table know so it can update the cell (if it’s visible). – Fogmeister May 21 ’13 at 14:28 |
|
What he is doing will force the download every single time he scrolls to that cell in the table. Whether the images are stored persistently is up to him, but at least store them for the life time of the tableview. – Fogmeister May 21 ’13 at 14:28 |
|
Exactly 😀 That way you only need to fetch the image from the URL once. You will see this on things like Facebook Friend Picker. When you start it all the avatars are grey placeholders. Then as you scroll they all fill in as it moves along. But then when you scroll back to a cell previously shown it will instantly show the already downloaded image. – Fogmeister May 21 ’13 at 14:41 |
show 4 more comments |
7 Answers
activeoldestvotes
|
|
Thanks. I believe you need to edit your answer. updateCell.poster.image = nil tocell.poster.image = nil; updateCell is called before it’s declared. – Segev May 21 ’13 at 7:09 |
|
@EXEC_BAD_ACCESS quite right. Thanks. – Rob May 21 ’13 at 7:11 |
|
@EXEC_BAD_ACCESS AFNetworking is a general networking class that eliminates a lot of uglyNSURLConnection programming. SDWebImage is a smaller framework, focusing primarily on images being retrieved from the web. Both do a pretty good job on their UIImageView categories. – Rob May 21 ’13 at 7:30 |
|
@Rob At this moment, I love you more than I love my girlfriend, I don’t have one but I’m sure I would love you more than her if thats the case, I had this stupid issue for a month now, and i’m delaying it everytime, but thanks to you NO MORE DELAYING! I fixed it! Make sure to get my app, maybe in less than a week, its called Feelit, we would be happy to have you aboard! xD – Albara Sep 15 ’13 at 13:31 |
|
This is one of the most beautiful solutions so far! Thanks! – jovanjovanovic Feb 27 ’14 at 4:00 |
|