I've released my app and noticed the jerkyness when scrolling in the CellForRowAtIndexPath, this is because i'm rendering an image from an JSON Feed via a URL. I've searched the internet and found a few examples and this one i've almost got working. The problem is when it renders the images don't match the correct title. Can someone please have a look and see what if i'm doing something obviously wrong.
Anyway here is my code:
- (void)displayImage:(UIImage *)image {
[photo setImage:image];
}
-(void)loadImage:(NSString *)url {
NSData* imageData = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:url]];
UIImage* image = [[[UIImage alloc] initWithData:imageData] autorelease];
[imageData release];
[self performSelectorOnMainThread:@selector(displayImage:) withObject:image waitUntilDone:NO];
}
CellForRowAtIndexPath Methord
#define DATELABEL_TAG 1 #define MAINLABEL_TAG 2 #define PHOTO_TAG 3 UIImageView *photo;
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *MainNewsCellIdentifier = @"MainNewsCellIdentifier";
UILabel *mainLabel, *dateLabel;
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier: MainNewsCellIdentifier];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier: MainNewsCellIdentifier] autorelease];
cell.accessoryType = UITableViewCellAccessoryDetailDisclosureButton;
dateLabel = [[[UILabel alloc] initWithFrame:CGRectMake(15.0,15.0,170.0,15.0)] autorelease];
dateLabel.tag = DATELABEL_TAG;
dateLabel.font = [UIFont systemFontOfSize:10.0];
dateLabel.textAlignment = UITextAlignmentLeft;
dateLabel.textColor = [UIColor darkGrayColor];
dateLabel.autoresizingMask = UIViewAutoresizingFlexibleRightMargin;
[cell.contentView addSubview:dateLabel]; 开发者_运维知识库
mainLabel = [[[UILabel alloc] initWithFrame:CGRectMake(15.0,28.0,170.0,60.0)] autorelease];
mainLabel.tag = MAINLABEL_TAG;
mainLabel.font = [UIFont boldSystemFontOfSize:14.0];
mainLabel.textColor = [UIColor blackColor];
mainLabel.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleRightMargin;
mainLabel.numberOfLines = 0;
[cell.contentView addSubview:mainLabel];
photo = [[[UIImageView alloc] initWithFrame:CGRectMake(190.0,15.0,85.0,85.0)] autorelease];
photo.tag = PHOTO_TAG;
photo.contentMode = UIViewContentModeScaleAspectFit;
[cell.contentView addSubview:photo];
}
else {
dateLabel = (UILabel *)[cell.contentView viewWithTag:DATELABEL_TAG];
mainLabel = (UILabel *)[cell.contentView viewWithTag:MAINLABEL_TAG];
photo = (UIImageView *)[cell.contentView viewWithTag:PHOTO_TAG];
}
NSUInteger row = [indexPath row];
NSDictionary *stream = (NSDictionary *) [dataList objectAtIndex:row];
NSString *title = [stream valueForKey:@"title"];
NSString *titleString = @"";
if( ! [title isKindOfClass:[NSString class]] )
{
titleString = @"";
}
else
{
titleString = title;
}
CGSize maximumSize = CGSizeMake(180, 9999);
UIFont *dateFont = [UIFont fontWithName:@"Helvetica" size:14];
CGSize dateStringSize = [titleString sizeWithFont:dateFont
constrainedToSize:maximumSize
lineBreakMode:mainLabel.lineBreakMode];
CGRect dateFrame = CGRectMake(15.0, 28.0, 170.0, dateStringSize.height);
mainLabel.frame = dateFrame;
mainLabel.text = titleString;
dateLabel.text = [stream valueForKey:@"created"];
NSString *i = [NSString stringWithFormat:@"http://www.domain.co.uk/images/stories/%@", [stream valueForKey:@"image"]];
photo.image = [UIImage imageNamed:@"i_digital_media.png"];
NSOperationQueue *queue = [NSOperationQueue new];
NSInvocationOperation *operation = [[NSInvocationOperation alloc]
initWithTarget:self
selector:@selector(loadImage:)
object:i];
[queue addOperation:operation];
[operation release];
return cell;}
By the time that your image is loaded, the photo variable is pointed to a different photo :)
You need to pass both the loaded image and the UIImageView you want to update back - try using a NSDictionary to pass variables between threads :
- (void)displayImage:(NSDictionary *)info {
[[info objectForKey:@"photo"] setImage:[info objectForKey:@"image"]];
}
-(void)loadImage:(NSDictionary *)info {
NSString *imagePath = [info objectForKey:@"imagePath"];
UIImageView *photo = [info objectForKey:@"photo"];
// Load the image
NSData* imageData = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:url]];
UIImage* image = [[[UIImage alloc] initWithData:imageData] autorelease];
[imageData release];
// Pass it back to the main thread
NSDictionary *mainThreadInfo = [NSdictionary dictionaryWithObjectAndKeys:image, @"image", photo, @"photo", nil];
[self performSelectorOnMainThread:@selector(displayImage:) withObject:mainThreadInfo waitUntilDone:YES];
}
so now, your operation will pass the photo and the image data back to the main thread. Create the operation like this :
NSDictionary *info = [NSDictionary dictionaryWithObjectsAndKeys:i, @"imagePath", photo, @"photo", nil];
NSInvocationOperation *operation = [[NSInvocationOperation alloc]
initWithTarget:self
selector:@selector(loadImage:)
object:info];
And get rid of the global photo variable :)
精彩评论