图像会自动添加到 UItableView Cell 中吗?
Posted
技术标签:
【中文标题】图像会自动添加到 UItableView Cell 中吗?【英文标题】:Image is getting added automatically in UItableView Cell? 【发布时间】:2015-10-24 05:11:51 【问题描述】:大家好,
我在这里遇到了一个非常奇怪的情况。我有一个表格视图,其中有自定义单元格。所以我设计了自己的自定义单元格。在自定义单元格中,我正在显示图像以及文本。表格的数据来自服务器。如果 json 中有任何图像,则将显示图像,否则仅显示文本。因此单元格将是动态的。我已经使用bezier path
将文本环绕在图像周围。如果图像存在,则文本将被包裹。当我从服务器添加带有图像的新帖子并刷新表格时,它也会自动显示其他帖子的图像。它将显示与最后相同的图像相同的图像。我不知道为什么新单元格在其单元格中添加图像即使代码工作正常我已经使用断点对其进行了调试。请告诉可能是什么问题。
这是cellForRowAtIndexPath
的代码
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
//define variables here
static NSString *CellIdentifier = @"homeCell";
HomeCell *cell = [tableView
dequeueReusableCellWithIdentifier:CellIdentifier
forIndexPath:indexPath];
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
if([arr_post count]>0)
NSMutableAttributedString *mutableAttributeStr;
NSAttributedString *attributeStr;
[cell layoutIfNeeded];
//get the post data
Post *user_post=[arr_post objectAtIndex:indexPath.row];
//set the button tags
cell.btn_like.tag=indexPath.row;
cell.btn_comment.tag=indexPath.row;
cell.btn_fav.tag=indexPath.row;
cell.btn_con.tag=indexPath.row;
cell.btn_book.tag=indexPath.row;
//add info to buttons
cell.btn_like.selected=user_post.isPostLiked;
cell.btn_comment.selected=user_post.isPostCommented;
cell.btn_fav.selected=user_post.isPostFavourite;
cell.btn_con.selected=user_post.isPostCondolence;
cell.btn_book.selected=user_post.isPostBookmarked;
//add user info
cell.label_name.text=user_post.username;
cell.img_profile.layer.cornerRadius = 25;
cell.img_profile.clipsToBounds = YES;
[cell.img_profile setImageWithURL:[NSURL URLWithString:[IMAGE_BASE_URL stringByAppendingString:user_post.user_profileImage]]placeholderImage:[UIImage imageNamed:@"post_placeholder.png"]];
//add location
if([user_post.location isEqualToString:@"Not Available"])
[cell.img_icon_location setHidden:true];
[cell.label_location setHidden:true];
else
[cell.img_icon_location setHidden:false];
[cell.label_location setHidden:false];
cell.label_location.text=user_post.location;
//ad post info
cell.tv_post.text=user_post.post_description;
cell.tv_post.font = [UIFont fontWithName:user_post.font_family size:[user_post.font_size floatValue]];
[cell.tv_post setTextColor:[self colorFromHexString:user_post.font_color]];
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
NSDate *date = [formatter dateFromString:user_post.modification_date];
NSLog(@"user post image is %@",user_post.post_image);
if([user_post.post_image isEqualToString:@"none"] && [user_post.post_video isEqualToString:@"none"])
NSLog(@"NOT INSIDE THE CONDITION");
else
NSLog(@"INSIDE BEIZER PATH CONDITION");
UIBezierPath * imgRect = [UIBezierPath bezierPathWithRect:CGRectMake(0, 10, 100, 100)];
cell.tv_post.textContainer.exclusionPaths = @[imgRect];
UIImageView *tv_image =[[UIImageView alloc]initWithFrame:CGRectMake(0, 10, 100, 100)];
if(![user_post.post_image isEqualToString:@"none"])
[tv_image setImageWithURL:[NSURL URLWithString:[IMAGE_BASE_URL stringByAppendingString:user_post.post_image]]placeholderImage:[UIImage imageNamed:@"post_placeholder.png"]];
if(![user_post.post_video isEqualToString:@"none"])
[tv_image setImageWithURL:[NSURL URLWithString:[IMAGE_BASE_URL stringByAppendingString:user_post.post_video_thumbnail]]placeholderImage:[UIImage imageNamed:@"post_placeholder.png"]];
[cell.tv_post addSubview:tv_image];
//make textview height dynamic
cell.tv_post.scrollEnabled=NO;
if([user_post.post_image isEqualToString:@"none"] && [user_post.post_video isEqualToString:@"none"])
CGFloat fixedWidth = cell.tv_post.frame.size.width;
CGSize newSize = [cell.tv_post sizeThatFits:CGSizeMake(fixedWidth, MAXFLOAT)];
CGRect newFrame = cell.tv_post.frame;
newFrame.size = CGSizeMake(fmaxf(newSize.width, fixedWidth), newSize.height);
cell.tv_post.frame = newFrame;
cell.tv_height.constant=cell.tv_post.frame.size.height;
[cell.view_tvContainer layoutIfNeeded];
//set the border of uiview
cell.view_tvContainer.layer.borderColor = [UIColor blackColor].CGColor;
cell.view_tvContainer.layer.borderWidth = 2.0f;
//set the like count
NSString *first_like_user=recent_like_name=user_post.recent_like_name;
NSLog(@"FIRST LIEK USER IS %@",first_like_user);
NSString *str_recent_like_name;
int count=(int)[first_like_user length];
int like_count=[user_post.like_count intValue];
if(like_count>0)
cell.label_like_count.lineBreakMode=NSLineBreakByWordWrapping;
[cell.label_like_count sizeToFit];
[cell.label_like_count setHidden:false];
NSString *str_like_count=[NSString stringWithFormat:@"%lu",(unsigned long)like_count-1];
if(like_count==1)
if([myUsername isEqualToString:first_like_user])
first_like_user=@"You like this post ";
count=3;
else
first_like_user=[first_like_user stringByAppendingString:@" like this post"];
else if(like_count==2)
if([first_like_user isEqualToString:myUsername])
first_like_user=@"You";
Post *temp_user_post=[copy_arr_user_post objectAtIndex:indexPath.row];
first_like_user=[first_like_user stringByAppendingString:@" and "];
if(temp_user_post.recent_like_name==nil)
temp_user_post.recent_like_name=@"";
str_recent_like_name=[temp_user_post.recent_like_name_two stringByAppendingString:@" like this post"];
first_like_user=[first_like_user stringByAppendingString:str_recent_like_name];
else
if(like_count>1000)
like_count=like_count/1000;
str_like_count=[NSString stringWithFormat:@"%lu",(unsigned long)like_count];
str_like_count=[str_like_count stringByAppendingString:@"k"];
first_like_user=[first_like_user stringByAppendingString:@" and "];
str_like_count=[str_like_count stringByAppendingString:@" others like this post"];
first_like_user=[first_like_user stringByAppendingString:str_like_count];
else
if([first_like_user isEqualToString:myUsername])
first_like_user=@"You";
first_like_user=[first_like_user stringByAppendingString:@" and "];
str_like_count=[str_like_count stringByAppendingString:@" others like this post"];
first_like_user=[first_like_user stringByAppendingString:str_like_count];
mutableAttributeStr = [[NSMutableAttributedString alloc]initWithString:first_like_user];
attributeStr = [[NSAttributedString alloc]initWithString:@"\n" attributes:@NSFontAttributeName : [UIFont fontWithName:@"HelveticaNeue-Bold" size:8]];
[mutableAttributeStr addAttribute:NSFontAttributeName value: [UIFont fontWithName:@"Helvetica-Bold" size:14.0] range:NSMakeRange(0, count)];
[mutableAttributeStr addAttribute:NSForegroundColorAttributeName value:[self colorFromHexString:@"#48a0dd"] range:NSMakeRange(0, count)];
[mutableAttributeStr appendAttributedString:attributeStr];
[cell.label_like_count setAttributedText:mutableAttributeStr];
else
[cell.label_like_count setHidden:true];
// show dynamic comment
NSMutableArray *user_comments=user_post.comments;
float comment_count=[user_post.comment_count intValue];
NSLog(@"ID IS %@",user_post.id);
if(comment_count>0)
//make label multiline
cell.first_comment.lineBreakMode=NSLineBreakByWordWrapping;
[cell.first_comment sizeToFit];
cell.second_cmment.lineBreakMode=NSLineBreakByWordWrapping;
[cell.second_cmment sizeToFit];
cell.third_comment.lineBreakMode=NSLineBreakByWordWrapping;
[cell.third_comment sizeToFit];
if(comment_count==1)
[cell.first_comment setHidden:false];
[cell.second_cmment setHidden:true];
[cell.third_comment setHidden:true];
else if(comment_count==2)
[cell.first_comment setHidden:false];
[cell.second_cmment setHidden:false];
[cell.third_comment setHidden:true];
else
[cell.first_comment setHidden:false];
[cell.second_cmment setHidden:false];
[cell.third_comment setHidden:false];
[cell.btn_more_comments setHidden:false];
for(l=0;l<[user_comments count];l++)
Comment *comment=[user_comments objectAtIndex:l];
NSString *comment_string=[comment.user_name stringByAppendingString:@" "];
comment_string=[comment_string stringByAppendingString:comment.comment];
int count=(int)[comment.user_name length];
NSMutableAttributedString* mutableAttributeStr = [[NSMutableAttributedString alloc]initWithString:comment_string];
NSAttributedString *attributeStr = [[NSAttributedString alloc]initWithString:@"\n" attributes:@NSFontAttributeName : [UIFont fontWithName:@"HelveticaNeue-Bold" size:8]];
[mutableAttributeStr addAttribute:NSFontAttributeName value: [UIFont fontWithName:@"Helvetica-Bold" size:14.0] range:NSMakeRange(0, count)];
[mutableAttributeStr addAttribute:NSForegroundColorAttributeName value:[self colorFromHexString:@"#48a0dd"] range:NSMakeRange(0, count)];
[mutableAttributeStr appendAttributedString:attributeStr];
// end of the repetitive pattern
if (l == 0)
[cell.first_comment setAttributedText:mutableAttributeStr];
else if (l == 1)
[cell.second_cmment setAttributedText:mutableAttributeStr];
else if (l == 2)
[cell.third_comment setAttributedText:mutableAttributeStr];
else
[cell.first_comment setHidden:true];
[cell.second_cmment setHidden:true];
[cell.third_comment setHidden:true];
[cell.btn_more_comments removeFromSuperview];
cell.label_time.text=[BaseController timeAgoStringFromDate:date];
[arr_indexpath addObject:indexPath];
return cell;
【问题讨论】:
Cell 对象被重用。您需要确保在重新使用单元格之前删除所有旧图像 我该怎么做。我已经搜索了一个多星期,但人们一直在讨论细胞重用、细胞重用、细胞重用。Nut 无法找到一个单一的解决方案以及一个很好的概述问题。你能告诉我我能做的最好吗。请 您的问题是您使用的是addSubview
,因此您会发现以后很难找到删除它的参考。您应该在单元格中包含 imageview 并根据需要隐藏/取消隐藏它
能否请您提供代码。sso 我可以更好地理解。我不是经验丰富的开发人员。只是使用 ios
为了在图像周围环绕文本,我使用的是贝泽路径,这就是为什么我要添加图像视图,如果我想在图像周围环绕文本,我必须这样做。
【参考方案1】:
请记住,单元格是重复使用的。如果您的表数据源中有 10000 行,则表视图不会创建那么多行。它只会创建足够的行以显示在屏幕上,而其他一些行将被预加载。
每次滚动表格时,表格视图将使用那些不可见的单元格来加载刚刚变得可见的新单元格,从而产生无限数量的行的错觉。这就是为什么那些新单元格有旧数据的原因。所以基本上,如果没有可用的图像,您必须将UIImageView
的图像设置为cellForRowAtIndexpath:
中的nil
。
if([user_post.post_image isEqualToString:@"none"] && [user_post.post_video isEqualToString:@"none"])
NSLog(@"NOT INSIDE THE CONDITION");
在你上面的代码中,你只是打印了一个日志,而你还需要做的是将UIImageView's
图像设置为nil
。
这是我的建议:
//if([user_post.post_image isEqualToString:@"none"] && [user_post.post_video isEqualToString:@"none"])
//
// NSLog(@"NOT INSIDE THE CONDITION");
//
//else
NSLog(@"INSIDE BEIZER PATH CONDITION");
UIBezierPath * imgRect = [UIBezierPath bezierPathWithRect:CGRectMake(0, 10, 100, 100)];
cell.tv_post.textContainer.exclusionPaths = @[imgRect];
UIImageView *tv_image =[[UIImageView alloc]initWithFrame:CGRectMake(0, 10, 100, 100)];
if(![user_post.post_image isEqualToString:@"none"])
[tv_image setImageWithURL:[NSURL URLWithString:[IMAGE_BASE_URL stringByAppendingString:user_post.post_image]]placeholderImage:[UIImage imageNamed:@"post_placeholder.png"]];
else
[tv_image setImage:nil]; //Prevent the old data to be shown
if(![user_post.post_video isEqualToString:@"none"])
[tv_image setImageWithURL:[NSURL URLWithString:[IMAGE_BASE_URL stringByAppendingString:user_post.post_video_thumbnail]]placeholderImage:[UIImage imageNamed:@"post_placeholder.png"]];
else
[tv_image setImage:nil];//Prevent the old data to be shown
[cell.tv_post addSubview:tv_image];
也许这段代码不符合您对数据显示方式的要求,但希望它可以帮助您了解这个想法!
【讨论】:
【参考方案2】:当需要显示一个 tableview 单元格时,您将创建一个新单元格或重新使用您之前创建但在屏幕上不再可见的一个单元格。由于您创建了 UIImageView
并将其添加到单元格中,因此当您重用它时,图像仍然存在。
要阻止这种情况发生,您需要保留对 imageview 的引用,以便下次可以将其删除。由于您是动态添加它们并且没有IBOutlet
,因此您最快的选择是为图像分配tag
UIImageView *tv_image =[[UIImageView alloc]initWithFrame:CGRectMake(0, 10, 100, 100)];
tv_image.tag = 21; // arbitrary number but must be unique to the image
通过标记图像,下次您可以访问它:
UIImageView *tv_image = (UIImageView*)[cell viewWithTag:21];
if (tv_image != nil)
tv_image.image = nil; // remove the image (or remove the image view from the cell etc)
请务必相应地重构代码,这样如果您从标签中找到图像,就不需要重新创建它等
【讨论】:
在您获取您的单元格 (HomeCell *cell = ...) 后立即放置我发布的第二个块以清除图像。然后,在您创建 tv_image 的地方应用标签。如果 tv_image 不是 nil,你可以跳过 initWithFrame 和 tag 等,因为它将使用回收的版本【参考方案3】:您的img_profile
被重复,因为您正在重复使用该单元格。
替换下面的代码
[cell.img_profile setImageWithURL:[NSURL URLWithString:[IMAGE_BASE_URL stringByAppendingString:user_post.user_profileImage]]placeholderImage:[UIImage imageNamed:@"post_placeholder.png"]];
使用以下代码:-
if (user_post.user_profileImage.length == 0)
cell.img_profile.hidden = true;
else
[cell.img_profile setImageWithURL:[NSURL URLWithString:[IMAGE_BASE_URL stringByAppendingString:user_post.user_profileImage]]placeholderImage:[UIImage imageNamed:@"post_placeholder.png"]];
解释:- 检查您的 json 是否包含用户个人资料图像,然后设置图像,否则隐藏个人资料图像视图。
【讨论】:
【参考方案4】:表格视图重用单元格。这意味着如果您将子视图添加到单元格中,就像您在 [cell.tv_post addSubview:tv_image]
行中所做的那样,那么该子视图在被重用时仍将在单元格中。
基本上,如果您将子视图添加到tableView:cellForRowAtIndexPath:
中的自定义单元格,您可能会犯错误。
首先将tv_image
视图设计为HomeCell
。 HomeView
应该有一个名为 tv_image
的插座,连接到故事板或 XIB 中的图像视图。当您需要tv_image
时,显示它。否则,隐藏它。
if([user_post.post_image isEqualToString:@"none"] && [user_post.post_video isEqualToString:@"none"])
NSLog(@"NOT INSIDE THE CONDITION");
cell.tv_image.image = nil;
cell.tv_image.hidden = YES;
cell.tv_post.textContainer.exclusionPaths = @[];
else
NSLog(@"INSIDE BEIZER PATH CONDITION");
UIBezierPath * imgRect = [UIBezierPath bezierPathWithRect:CGRectMake(0, 10, 100, 100)];
cell.tv_post.textContainer.exclusionPaths = @[imgRect];
if(![user_post.post_image isEqualToString:@"none"])
[cell.tv_image setImageWithURL:[NSURL URLWithString:[IMAGE_BASE_URL stringByAppendingString:user_post.post_image]]placeholderImage:[UIImage imageNamed:@"post_placeholder.png"]];
if(![user_post.post_video isEqualToString:@"none"])
[cell.tv_image setImageWithURL:[NSURL URLWithString:[IMAGE_BASE_URL stringByAppendingString:user_post.post_video_thumbnail]]placeholderImage:[UIImage imageNamed:@"post_placeholder.png"]];
cell.tv_image.hidden = NO;
另外,请确保setImageWithURL:placeholderImage:
在加载图像时不会设置图像视图的hidden = NO
。
【讨论】:
如何从每个新的 textview 中删除 beizer 路径。你在这里看到我还在 textview 中添加 beizer 路径,所以当图像被删除时,beizer 路径必须被删除 我无法从情节提要设计,因为我使用的是贝泽路径,所以我想在此处将文本环绕在图像周围。 然后在HomeCell
代码中创建图像视图(并将其添加为子视图)并将其存储在属性中,以便您可以在表视图控制器中访问它。当没有 tv_image
可显示时,我已更新我的代码以将 exclusionPaths
重置为空数组。【参考方案5】:
我想知道您在哪里分配自定义单元格。难道您不应该仅在未创建单元格的情况下创建单元格。像这样的:
static NSString *CellIdentifier = @"homeCell";
HomeCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
if(!cell)
cell = [[[HomeCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier]];
然后更新 UI 组件。
if([user_post.post_image isEqualToString:@"none"] && [user_post.post_video isEqualToString:@"none"])
NSLog(@"NOT INSIDE THE CONDITION");
else
NSLog(@"INSIDE BEIZER PATH CONDITION");
UIBezierPath * imgRect = [UIBezierPath bezierPathWithRect:CGRectMake(0, 10, 100, 100)];
cell.tv_post.textContainer.exclusionPaths = @[imgRect];
UIImageView *tv_image =[[UIImageView alloc]initWithFrame:CGRectMake(0, 10, 100, 100)];
if(![user_post.post_image isEqualToString:@"none"])
[tv_image setImageWithURL:[NSURL URLWithString:[IMAGE_BASE_URL stringByAppendingString:user_post.post_image]]placeholderImage:[UIImage imageNamed:@"post_placeholder.png"]];
if(![user_post.post_video isEqualToString:@"none"])
[tv_image setImageWithURL:[NSURL URLWithString:[IMAGE_BASE_URL stringByAppendingString:user_post.post_video_thumbnail]]placeholderImage:[UIImage imageNamed:@"post_placeholder.png"]];
[cell.tv_post addSubview:tv_image];
也许您应该在“HomeCell”类中编写一个“更新方法”。更新 UI 组件。
【讨论】:
【参考方案6】:我建议使用 [SDWebImage][1]https://github.com/rs/SDWebImage ,如果需要,您可以在完成块中更新您的单元格或缓存图像
【讨论】:
【参考方案7】:问题有两个方面:
-
细胞被重复使用,这是错过的常见地方,但在你的情况下不是。
您的
[cell.img_profile setImageWithURL:...];
行是异步,这意味着在下载图像时,您的单元格可能会被重复使用,因此在重复使用时清除 imageView 不会帮助。
要在可重用单元格中正确使用图像的异步加载,您必须仔细检查它是否是正确的图像加载成功。
向单元格类添加属性:
@property (weak) NSURL *targetImageUrl;
然后更改加载以添加检查:
NSURL *targetImageUrl = [NSURL URLWithString:[IMAGE_BASE_URL stringByAppendingString:user_post.user_profileImage]];
cell.targetImageUrl = targetImageUrl; // <!> replace latest target
[cell.img_profile
setImageWithURLRequest: [NSMutableURLRequest requestWithURL:targetImageUrl]
placeholderImage: [UIImage imageNamed:@"post_placeholder.png"]
success: ^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image)
if (cell.targetImageUrl != targetImageUrl) return; // <!> this is the trick
cell.img_profile.image = image;
failure: ^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error)
];
【讨论】:
【参考方案8】:由于每当单元格变得可见时都会调用 cellForRowAtIndexPath,所以我总是使用下一个策略来显示需要从 Web 加载的图像:我将图像(下载时)与 objc_setAssociatedObject 与包含以下数据的对象相关联表行,或创建一些 hashMap,我将带有一些 id 作为键的图像放在其中。然后在 cellForRowAtIndexPath 中检查关联对象是否为 nil(或者键的图像是否存在于 hashmap 中)。如果它为 nil 或不存在(这意味着它仍在下载),我为 imageView 的图像设置一个占位符图像,否则我设置下载的图像。 下载后重新加载表格(或只是需要的单元格)
【讨论】:
以上是关于图像会自动添加到 UItableView Cell 中吗?的主要内容,如果未能解决你的问题,请参考以下文章
iOS8 UITableView 和 Cell - 自动布局高度 - 触摸和执行 segue 时的移位/垂直偏移错误