Adjusting Cell fields - Objective C - ios

I have a dynamically set table view controller that is used to populate a news type feed. I am having trouble connecting one class to the other for setting the text, image, etc... of that current cell.
Here is the gist:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"timelineCell";
FBGTimelineCell *cell = (FBGTimelineCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
cell.text = [self.googlePlacesArrayFromAFNetworking[indexPath.row] objectForKey:#"message"]; <!-- here is where I want to for example, set the title to the message within this array.
if (!cell)
{
cell = [[FBGTimelineCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
[cell initTimelineCell];
}
UIImage *img = [UIImage imageNamed:[NSString stringWithFormat:#"%d.jpg", indexPath.row]];
cell.photoView.image = img;
return cell;
}
Here is the FBH... init function:
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
// Initialization code
cellContentView = [[UIView alloc] initWithFrame:CGRectMake(10, 5, 300, 440)];
cellContentView.backgroundColor = [UIColor whiteColor];
photoView = [[FBGTimelinePhotoView alloc] initWithFrame:CGRectMake(5, 102, 310, 310)];
photoView.backgroundColor = [UIColor darkGrayColor];
[photoView setUserInteractionEnabled:YES];
UIView *profilePic = [[UIView alloc] initWithFrame:CGRectMake(9, 9, 30, 30)];
profilePic.backgroundColor = [UIColor darkGrayColor];
UILabel *usernameLabel = [[UILabel alloc] initWithFrame:CGRectMake(45, 9, 222, 18)];
usernameLabel.font = [UIFont systemFontOfSize:14.0];
usernameLabel.text = #"Username";
UILabel *timestampLabel = [[UILabel alloc] initWithFrame:CGRectMake(45, 25, 222, 17)];
timestampLabel.font = [UIFont systemFontOfSize:12.0];
timestampLabel.text = #"3 hours ago";
timestampLabel.textColor = [UIColor lightGrayColor];
UILabel *statusLabel = [[UILabel alloc] initWithFrame:CGRectMake(9, 50, 283, 41)];
statusLabel.font = [UIFont systemFontOfSize:15.0];
statusLabel.text = #"Status..status..status..status..status..status..status..status..status..status..status..status..status..status..status..";
statusLabel.numberOfLines = 2;
statusLabel.lineBreakMode = NSLineBreakByWordWrapping;
UILabel *likeLabel = [[UILabel alloc] initWithFrame:CGRectMake(9, 413, 32, 21)];
likeLabel.font = [UIFont systemFontOfSize:13.0];
likeLabel.text = #"Like";
UILabel *commentLabel = [[UILabel alloc] initWithFrame:CGRectMake(113, 413, 74, 21)];
commentLabel.font = [UIFont systemFontOfSize:13.0];
commentLabel.text = #"Comment";
UILabel *shareLabel = [[UILabel alloc] initWithFrame:CGRectMake(246, 413, 46, 21)];
shareLabel.font = [UIFont systemFontOfSize:13.0];
shareLabel.text = #"Share";
[self addSubview:cellContentView];
[self addSubview:photoView];
[cellContentView addSubview:profilePic];
[cellContentView addSubview:usernameLabel];
[cellContentView addSubview:timestampLabel];
[cellContentView addSubview:statusLabel];
[cellContentView addSubview:likeLabel];
[cellContentView addSubview:commentLabel];
[cellContentView addSubview:shareLabel];
}
return self;
}
So I need to be able to set the cell text and different views within the cell within the cellForRowAtIndexPath if possible for each cell that is set up in the FB..init function.
Suggestions, thoughts?

You should create properties (in the FBGTimelineCell class) for each of the UI elements that you need to access in cellFroRowAtIndexPath, then you can access them with cell.propertyName.

You can create properties for all the dynamic values which are expected to be changed with each cell. Those properties you can set in your cellForRowAtIndexPath method.
eg. cell.statusText = [NSString stringWithFormat:#"%# is rocking!!", indexPath.row];
Public properties like statusText you can add all the UIElements expecting to be dynamically added.
Hope it helps.
Cheers.

Related

IOS, How to set Auto Layout in your UITableViewCell that contains different Subviews

I have a layout issue, i have a UIView that contains an UIImageView and three other UILabels. The part that needs to set the layout dynamically is the main UIView thats added to the cell and a UILabel that will contain text of any length lets say for this example.
What i have done i created a custom UITableViewCell and added the SubViews to the custom UITableViewCell, like here:
-(void)setupView:(PostInfo*)postInfo{
CGRect screenRect = [[UIScreen mainScreen] bounds];
viewPostMessage = [[UIView alloc] initWithFrame:CGRectMake(10, 10, screenRect.size.width - 20, 100)];
viewPostMessage.backgroundColor = [UIColor colorWithRed:193.0f/255 green:193.0f/255 blue:193.0f/255 alpha:1.0f];
viewPostMessage.layer.borderColor = [UIColor blackColor].CGColor;
viewPostMessage.layer.borderWidth = 0.5f;
if(postInfo.userImage.length > 0){
userImage = [[UIImageView alloc] initWithFrame:CGRectMake(10, 10, 30, 30)];
UIImage *imageUser = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString: [NSString stringWithFormat:#"http://www.hugt.co.uk/userimage/%d/userImage.jpg", postInfo.userId]]]];
userImage.image = imageUser;
[viewPostMessage addSubview:userImage];
}else{
UIView *viewImage = [[UIView alloc] initWithFrame:CGRectMake(10, 10, 30, 30)];
viewImage.backgroundColor = [UIColor colorWithRed:132.0f/255 green:132.0f/255 blue:132.0f/255 alpha:1.0f];
[viewPostMessage addSubview:viewImage];
userImage = [[UIImageView alloc] initWithFrame:CGRectMake(5, 5, 20, 20)];
UIImage *imageUser = [UIImage imageNamed:#"defaultuser.jpg"];
userImage.image = imageUser;
[viewImage addSubview:userImage];
}
labelUserName = [[UILabel alloc] initWithFrame:CGRectMake(50, 8, 200, 16)];
labelUserName.textColor = [UIColor colorWithRed:56.0f/255 green:56.0f/255 blue:57.0f/255 alpha:1.0f];
labelUserName.text = [NSString stringWithFormat:#"%# %# posted...", postInfo.firstName,postInfo.lastName];
//labelFirstName.textAlignment = NSTextAlignmentCenter;
labelUserName.font = [UIFont fontWithName:#"Helvetica" size:12];
labelUserName.userInteractionEnabled = YES;
[viewPostMessage addSubview:labelUserName];
labelCreated = [[UILabel alloc] initWithFrame:CGRectMake(50, 24, 200, 16)];
labelCreated.textColor = [UIColor colorWithRed:86.0f/255 green:152.0f/255 blue:179.0f/255 alpha:1.0f];
labelCreated.text = [NSDateFormatter localizedStringFromDate:postInfo.timeStampCreated dateStyle:NSDateFormatterMediumStyle timeStyle:NSDateFormatterMediumStyle];
labelCreated.text = [labelCreated.text stringByReplacingOccurrencesOfString:#"AM" withString:#""];
labelCreated.text = [labelCreated.text stringByReplacingOccurrencesOfString:#"PM" withString:#""];
//labelFirstName.textAlignment = NSTextAlignmentCenter;
labelCreated.font = [UIFont fontWithName:#"Helvetica" size:12];
labelCreated.userInteractionEnabled = YES;
[viewPostMessage addSubview:labelCreated];
labelMessage = [[UILabel alloc] initWithFrame:CGRectMake(50, 43, 210, 50)];
labelMessage.textColor = [UIColor colorWithRed:141.0f/255 green:142.0f/255 blue:142.0f/255 alpha:1.0f];
labelMessage.text = postInfo.message;
labelMessage.numberOfLines = 3;
//labelFirstName.textAlignment = NSTextAlignmentCenter;
labelMessage.font = [UIFont fontWithName:#"Helvetica" size:12];
labelMessage.userInteractionEnabled = YES;
[labelMessage sizeToFit];
[viewPostMessage addSubview:labelMessage];
[self.contentView addSubview:viewPostMessage];
}
When i create this custom UITableViewCell i pass in an object that sets the text on the UILabels, like this:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *cellIdentifier = #"cell";
if(tableViewThreads == tableView){
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellIdentifier];
}
ThreadInfo *threadInfo = (ThreadInfo*)[self.threadsArray objectAtIndex:indexPath.row];
[cell.contentView addSubview:[self setupThreadItem:threadInfo]];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
return cell;
}
if(tableViewPosts == tableView){
PostTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil)
{
cell = [[PostTableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellIdentifier];
}
PostInfo *postInfo = (PostInfo*)[self.postsArray objectAtIndex:indexPath.row];
[cell setupView:postInfo];
//[cell addSubview:[self setupPostItem:postInfo]];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
return cell;
//[cell.contentView addSubview:[self setupThreadItem:threadInfo]];
}
return nil;
}
I have searched the web and also here to find out how to Auto Layout the Subviews in the cell but can't seem to understand what needs to go next. I read that you need a Prototype Cell so i created a custom UITableViewCell and thats how far I've got.
Any help would be appreciated, thanks.
So far i have got the cells to resize with Auto Layout but i have removed the UIView that sits inside the cell, so now i have three UILabels and an UIImageView which are the UIImageView (userImage), UILabel (labelUsername), UILabel (labelCreated) and UILabel (labelMessage). So the dimensions and coordinates are the same just that the UIView has been removed:
First i set up NSLayoutContsraints in my Custom Cell, code bellow:
Set numberOFLines = 0 and remove sizeToFit on the UILabel thats going to AutoLayout.
-(void)setupView:(PostInfo*)postInfo{
CGRect screenRect = [[UIScreen mainScreen] bounds];
viewPostMessage = [[UIView alloc] initWithFrame:CGRectMake(10, 10, screenRect.size.width - 20, 100)];
viewPostMessage.backgroundColor = [UIColor colorWithRed:193.0f/255 green:193.0f/255 blue:193.0f/255 alpha:1.0f];
viewPostMessage.layer.borderColor = [UIColor blackColor].CGColor;
viewPostMessage.layer.borderWidth = 0.5f;
if(postInfo.userImage.length > 0){
userImage = [[UIImageView alloc] initWithFrame:CGRectMake(10, 10, 30, 30)];
UIImage *imageUser = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString: [NSString stringWithFormat:#"http://www.hugt.co.uk/userimage/%d/userImage.jpg", postInfo.userId]]]];
userImage.image = imageUser;
[self.contentView addSubview:userImage];
}else{
UIView *viewImage = [[UIView alloc] initWithFrame:CGRectMake(10, 10, 30, 30)];
viewImage.backgroundColor = [UIColor colorWithRed:132.0f/255 green:132.0f/255 blue:132.0f/255 alpha:1.0f];
[self.contentView addSubview:viewImage];
userImage = [[UIImageView alloc] initWithFrame:CGRectMake(5, 5, 20, 20)];
UIImage *imageUser = [UIImage imageNamed:#"defaultuser.jpg"];
userImage.image = imageUser;
[viewImage addSubview:userImage];
}
labelUserName = [[UILabel alloc] initWithFrame:CGRectMake(50, 8, 200, 16)];
labelUserName.textColor = [UIColor colorWithRed:56.0f/255 green:56.0f/255 blue:57.0f/255 alpha:1.0f];
labelUserName.text = [NSString stringWithFormat:#"%# %# posted...", postInfo.firstName,postInfo.lastName];
//labelFirstName.textAlignment = NSTextAlignmentCenter;
labelUserName.font = [UIFont fontWithName:#"Helvetica" size:12];
labelUserName.userInteractionEnabled = YES;
[self.contentView addSubview:labelUserName];
labelCreated = [[UILabel alloc] initWithFrame:CGRectMake(50, 24, 200, 16)];
labelCreated.textColor = [UIColor colorWithRed:86.0f/255 green:152.0f/255 blue:179.0f/255 alpha:1.0f];
labelCreated.text = [NSDateFormatter localizedStringFromDate:postInfo.timeStampCreated dateStyle:NSDateFormatterMediumStyle timeStyle:NSDateFormatterMediumStyle];
labelCreated.text = [labelCreated.text stringByReplacingOccurrencesOfString:#"AM" withString:#""];
labelCreated.text = [labelCreated.text stringByReplacingOccurrencesOfString:#"PM" withString:#""];
//labelFirstName.textAlignment = NSTextAlignmentCenter;
labelCreated.font = [UIFont fontWithName:#"Helvetica" size:12];
labelCreated.userInteractionEnabled = YES;
[self.contentView addSubview:labelCreated];
labelMessage = [[UILabel alloc] initWithFrame:CGRectMake(50, 43, 210, 50)];
labelMessage.textColor = [UIColor colorWithRed:141.0f/255 green:142.0f/255 blue:142.0f/255 alpha:1.0f];
labelMessage.text = postInfo.message;
labelMessage.numberOfLines = 0;
//labelFirstName.textAlignment = NSTextAlignmentCenter;
labelMessage.font = [UIFont fontWithName:#"Helvetica" size:12];
labelMessage.userInteractionEnabled = YES;
labelMessage.lineBreakMode = NSLineBreakByWordWrapping;
//[labelMessage sizeToFit];
[self.contentView addSubview:labelMessage];
labelMessage.translatesAutoresizingMaskIntoConstraints = NO;
[self.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-10-[bodyLabel]-19-|" options:0 metrics:nil views:#{ #"bodyLabel": labelMessage }]];
[self.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|-43-[bodyLabel]-6-|" options:0 metrics:nil views:#{ #"bodyLabel": labelMessage }]];
//[self.contentView addSubview:viewPostMessage];
}
Then in my ViewController that contains the UITableVIew, i modified this bit of code:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *cellIdentifier = #"cell";
if(tableViewThreads == tableView){
return 122;
}
if(tableViewPosts == tableView){
PostTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil)
{
cell = [[PostTableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellIdentifier];
}
PostInfo *postInfo = (PostInfo*)[self.postsArray objectAtIndex:indexPath.row];
[cell setupView:postInfo];
[cell setNeedsLayout];
[cell layoutIfNeeded];
CGFloat h = [cell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;
return h + 1;
}
return 0;
}
The Cells do now resize and the UILabel resizes automatically now but my other problem is that the UITableView scroll is not smooth so ill have to fix that, and when i scroll in the UITableView the Cell data from the UILabel (labelMessage) seems to print it self in other cells, don't know why this is
BUT the Cells resize and the other issues ill ask another question on here.
Sorry forgot to add this bit of code that sits in the PostTableViewCell:
- (void)layoutSubviews
{
[super layoutSubviews];
// Make sure the contentView does a layout pass here so that its subviews have their frames set, which we
// need to use to set the preferredMaxLayoutWidth below.
[self.contentView setNeedsLayout];
[self.contentView layoutIfNeeded];
// Set the preferredMaxLayoutWidth of the mutli-line bodyLabel based on the evaluated width of the label's frame,
// as this will allow the text to wrap correctly, and as a result allow the label to take on the correct height.
labelMessage.preferredMaxLayoutWidth = CGRectGetWidth(labelMessage.frame);
}

cellForRowAtIndexPath and sizeToFit reduces label width when scrolling

I've a custom cell with labels init in a UITableViewCell.
In my cellForRowAtIndexPath method after setting label content i call sizeToFit on the label to get the correct width and height, but when i scroll in my TableView, the label width reduce on each cells, every time i scroll.
Anyone for help ?
Thanks
My custom UITableViewCell
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
CGRect viewBounds = self.contentView.bounds;
// marge
CGFloat margin = 20;
self.excuse_date = [[UILabel alloc] initWithFrame:CGRectMake(5, 10, 300, 30)];
self.excuse_date.textColor = [UIColor blackColor];
self.excuse_date.font = [UIFont fontWithName:#"Arial" size:12.0f];
[self addSubview:self.excuse_date];
static CGFloat dateWidth = 130;
self.excuse_date.frame = CGRectMake(viewBounds.size.width-dateWidth-35, margin, dateWidth, 20);
CGRect dateFrame = self.excuse_date.frame;
self.excuse_date.textAlignment = NSTextAlignmentRight;
// setup excuse_auteur
self.excuse_auteur = [[UILabel alloc] init];
self.excuse_auteur.font = [UIFont fontWithName:#"Helvetica" size:13];
self.excuse_auteur.textColor = [UIColor darkGrayColor];
self.excuse_auteur.textAlignment = NSTextAlignmentLeft;
self.excuse_auteur.frame = CGRectMake(margin, margin, viewBounds.size.width-dateWidth-(margin*2), 20);
[self addSubview:self.excuse_auteur];
// setup excuse_texte
self.excuse_texte = [[UILabel alloc] initWithFrame:CGRectMake(20, CGRectGetMaxY(dateFrame)+margin/2, viewBounds.size.width - (margin*3), 200)];
self.excuse_texte.lineBreakMode = NSLineBreakByWordWrapping;
self.excuse_texte.numberOfLines = 0;
self.excuse_texte.font = [UIFont fontWithName:#"Helvetica" size:17];
self.excuse_texte.autoresizingMask = UIViewAutoresizingNone;
[self addSubview:self.excuse_texte];
CGRect textFrame = self.excuse_texte.frame;
// setup up image
UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"up-small"]];
self.img = imageView;
[self addSubview:self.img];
imageView.frame = CGRectMake(20, CGRectGetMaxY(textFrame)+margin/2, 20, 20);
// setup up
self.up = [[UILabel alloc] initWithFrame:CGRectMake(45, CGRectGetMaxY(textFrame)+margin/2+2, viewBounds.size.width - margin*2, 20)];
self.up.font = [UIFont fontWithName:#"Helvetica" size:11];
self.up.textColor = [UIColor darkGrayColor];
self.up.textAlignment = NSTextAlignmentLeft;
[self addSubview:self.up];
}
return self;
}
My cellForRowAtIndexPath method
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
BBExcuse *excuse = [self.list objectAtIndex:indexPath.row];
static NSString *cellIdentifier = #"Cell";
// Similar to UITableViewCell, but
BBTableViewCell *cell = (BBTableViewCell *)[tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) {
cell = [[BBTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
cell.excuse_texte.text = excuse.excuse_texte;
// #TODO problem here ?
[cell.excuse_texte sizeToFit];
cell.excuse_auteur.text = excuse.excuse_auteur;
cell.excuse_date.text = excuse.excuse_date;
cell.up.text = [NSString stringWithFormat:#"%#", excuse.up];
cell.img.frame = CGRectMake(20, CGRectGetMaxY(cell.excuse_texte.frame)+20/2, 20, 20);
cell.up.frame = CGRectMake(45, CGRectGetMaxY(cell.excuse_texte.frame)+20/2+2, 20, 20);
// setup up
return cell;
}
Ok solved by removing sizeToFit and specify height and width in cellForRowAtIndexPath
cell.excuse_texte.text = excuse.excuse_texte;
NSString *str = excuse.excuse_texte;
UILabel *gettingSizeLabel = [[UILabel alloc] init];
gettingSizeLabel.font = [UIFont systemFontOfSize:17];
gettingSizeLabel.text = str;
gettingSizeLabel.numberOfLines = 0;
gettingSizeLabel.lineBreakMode = NSLineBreakByWordWrapping;
CGSize maximumLabelSize = CGSizeMake(260.0f, 9999.0f);
CGSize theSize = [gettingSizeLabel sizeThatFits:maximumLabelSize];
// on resize sans sizetofit
cell.excuse_texte.frame = CGRectMake(cell.excuse_texte.frame.origin.x, cell.excuse_texte.frame.origin.y, cell.excuse_texte.frame.size.width, theSize.height);

iOS how to add UIView to tableview cell effectively

I have a table going where each cell has a UIView in it that is fed from an XMLParser feed. If I leave it how it is, each time I refresh the views build upon each other because they are not getting released/removed, which makes total sense. How would I go about writing my code to avoid that problem, and not having to rebuild the view's each time I refresh. I am stuck in the logic of it and also the actual syntax. Thanks.
Code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
JointCAD *currentCall = [[xmlParser calls] objectAtIndex:indexPath.row];
self.tableView.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"texture.png"]];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
UIView *selectionView = [[UIView alloc] initWithFrame:CGRectMake(10, 7, 200, 65)];
[selectionView setBackgroundColor: [UIColor clearColor]];
cell.selectedBackgroundView = selectionView;
}
// Display content in each cell
cellSeparator = [[UIView alloc] initWithFrame:CGRectMake(10, 7, 300, 65)];
[cellSeparator setAutoresizingMask:UIViewAutoresizingFlexibleLeftMargin |
UIViewAutoresizingFlexibleRightMargin |
UIViewAutoresizingFlexibleWidth];
[cellSeparator setContentMode:UIViewContentModeTopLeft];
[cellSeparator setBackgroundColor: [UIColor colorWithRed:240.0/255.0 green:240.0/255.0 blue:240.0/255.0 alpha:1.0]];
cellSeparator.layer.borderWidth = 1.0;
cellSeparator.layer.borderColor = [UIColor blackColor].CGColor;
[cell addSubview:cellSeparator];
callTypeLabel = [[UILabel alloc]initWithFrame:CGRectMake(5, 2, 190, 21)];
callTypeLabel.text = [currentCall currentCallType];
callTypeLabel.backgroundColor = [UIColor clearColor];
callTypeLabel.font = [UIFont boldSystemFontOfSize:12.0];
[cellSeparator addSubview:callTypeLabel];
locationLabel = [[UILabel alloc]initWithFrame:CGRectMake(5, 17 , 190, 15)];
locationLabel.text = [currentCall location];
locationLabel.backgroundColor = [UIColor clearColor];
locationLabel.font = [UIFont systemFontOfSize:10.0];
[cellSeparator addSubview:locationLabel];
unitsLabel = [[UILabel alloc]initWithFrame:CGRectMake(4, 43, 190, 21)];
unitsLabel.text = [currentCall units];
unitsLabel.backgroundColor = [UIColor clearColor];
unitsLabel.font = [UIFont italicSystemFontOfSize:10.0];
[cellSeparator addSubview:unitsLabel];
stationLabel = [[UILabel alloc]initWithFrame:CGRectMake(195 , 25, 75, 20)];
NSString *station = [#"Station: " stringByAppendingString:currentCall.station];
stationLabel.text = station;
stationLabel.backgroundColor = [UIColor clearColor];
stationLabel.font = [UIFont boldSystemFontOfSize:11.0];
[cellSeparator addSubview:stationLabel];
if ([currentCall.county isEqualToString:#"W"]) {
UIImage *countyImage = [UIImage imageNamed:#"blue.png"];
CGRect countyImageFrame = CGRectMake(275, 10, 18, 18);
UIImageView *countyImageLabel = [[UIImageView alloc] initWithFrame:countyImageFrame];
countyImageLabel.image = countyImage;
[cellSeparator addSubview:countyImageLabel];
} else {
UIImage *countyImage = [UIImage imageNamed:#"green.png"];
CGRect countyImageFrame = CGRectMake(275, 10, 18, 18);
UIImageView *countyImageLabel = [[UIImageView alloc] initWithFrame:countyImageFrame];
countyImageLabel.image = countyImage;
[cellSeparator addSubview:countyImageLabel];
}
if ([currentCall.callType isEqualToString:#"F"]) {
UIImage *callTypeImage = [UIImage imageNamed:#"red.png"];
CGRect callTypeImageFrame = CGRectMake(275, 37, 18, 18);
UIImageView *callTypeImageLabel = [[UIImageView alloc] initWithFrame:callTypeImageFrame];
callTypeImageLabel.image = callTypeImage;
[cellSeparator addSubview:callTypeImageLabel];
} else {
UIImage *callTypeImage = [UIImage imageNamed:#"yellow.png"];
CGRect callTypeImageFrame = CGRectMake(275, 37, 18, 18);
UIImageView *callTypeImageLabel = [[UIImageView alloc] initWithFrame:callTypeImageFrame];
callTypeImageLabel.image = callTypeImage;
[cellSeparator addSubview:callTypeImageLabel];
}
return cell;
}
If I understand your question correctly, I think the solution you want is to subclass UITableViewCell, set up your subviews (UIImageViews and all that) and make them properties on your subclass. Then you can
if (!cell.imageView) {
cell.imageView = [[UIImageView alloc] initWithFrame:myFrame];
}
then just set the image. That way you're sure to not stack image views on top of one another and the correct image will get set when the cell is dequeued.
EDIT:
Make a class called MyTableViewCell (or whatever you want to call it but make sure it's a subclass of UITableViewCell)
Add #property (strong, nonatomic) UIImageView *imageView;
Then use MyTableViewCell instead of UITableViewCell in you cellForRowAtIndexPath and you can access the image property of your custom table view cell, check if it exists, if not create it (which is what the above code does) and then set the image. I would give you code but I'm on my phone. Google subclassing UITableviewCell. You should find a ton of examples.

iOS GCD use for a UITableView

I have a pretty intensive UITableView that needs to be optimized a little. The question is, how to use grand central station to do it effectively. Each cell has a UIView with a couple labels and two images. I have subclassed the TableViewCell and the view's are being reused though it is still a little laggy when the table gets bigger. How would I go about using GCD to optimize the table? OR is there a better way around it? I am not very strong in thread management and looking for some advice.
Here is the code to my tableview:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
JointCAD *currentCall = [[xmlParser calls] objectAtIndex:indexPath.row];
self.tableView.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"texture3.png"]];
TableViewCell *cell = (TableViewCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[TableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
cell.callTypeLabel.text = currentCall.currentCallType;
cell.locationLabel.text = currentCall.location;
cell.unitsLabel.text = currentCall.units;
cell.stationLabel.text = [#"Station: " stringByAppendingString:currentCall.station];
cell.selectedBackgroundView = cell.selectionView;
if ([currentCall.callType isEqualToString:#"F"]) {
cell.imageType = Fire;
}
else {
cell.imageType = EMS;
}
if ([currentCall.county isEqualToString:#"W"]) {
cell.imageType1 = Washington;
}
else {
cell.imageType1 = Clackamas;
}
return cell;
}
Here is the subclassed tableviewcell:
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) {
callView = [[UIView alloc] initWithFrame:CGRectMake(7.5, 7, 305, 65)];
[callView setAutoresizingMask:UIViewAutoresizingFlexibleLeftMargin |
UIViewAutoresizingFlexibleRightMargin |
UIViewAutoresizingFlexibleWidth];
[callView setContentMode:UIViewContentModeTopLeft];
[callView setBackgroundColor: [UIColor colorWithRed:240.0/255.0 green:240.0/255.0 blue:240.0/255.0 alpha:1.0]];
callView.layer.borderWidth = 1.0;
callView.layer.borderColor = [UIColor colorWithRed:(0/255.0) green:(0/255.0) blue:(0/255.0) alpha:1.0].CGColor;
[self.contentView addSubview:callView];
callTypeLabel = [[UILabel alloc]initWithFrame:CGRectMake(5, 2, 190, 21)];
callTypeLabel.font = [UIFont boldSystemFontOfSize:12.0];
callTypeLabel.textColor = [UIColor blackColor];
callTypeLabel.backgroundColor = [UIColor clearColor];
callTypeLabel.highlightedTextColor = [UIColor whiteColor];
callTypeLabel.adjustsFontSizeToFitWidth = YES;
[callView addSubview:callTypeLabel];
locationLabel = [[UILabel alloc]initWithFrame:CGRectMake(5, 17 , 190, 15)];
locationLabel.font = [UIFont systemFontOfSize:10.0];
locationLabel.textColor = [UIColor blackColor];
locationLabel.backgroundColor = [UIColor clearColor];
locationLabel.highlightedTextColor = [UIColor whiteColor];
locationLabel.adjustsFontSizeToFitWidth = YES;
[callView addSubview:locationLabel];
unitsLabel = [[UILabel alloc]initWithFrame:CGRectMake(4, 43, 190, 21)];
unitsLabel.font = [UIFont systemFontOfSize:10.0];
unitsLabel.textColor = [UIColor blackColor];
unitsLabel.backgroundColor = [UIColor clearColor];
unitsLabel.highlightedTextColor = [UIColor whiteColor];
unitsLabel.adjustsFontSizeToFitWidth = NO;
[callView addSubview:unitsLabel];
stationLabel = [[UILabel alloc]initWithFrame:CGRectMake(195 , 25, 75, 20)];
stationLabel.font = [UIFont systemFontOfSize:12.0];
stationLabel.textColor = [UIColor blackColor];
stationLabel.backgroundColor = [UIColor clearColor];
stationLabel.highlightedTextColor = [UIColor whiteColor];
stationLabel.adjustsFontSizeToFitWidth = YES;
[callView addSubview:stationLabel];
CGRect countyImageFrame = CGRectMake(275, 10, 18, 18);
UIImageView *countyImageView = [[UIImageView alloc] initWithFrame:countyImageFrame];
countyImageView.image = countyImage;
[callView addSubview:countyImageView];
CGRect callTypeImageFrame = CGRectMake(275, 37, 18, 18);
UIImageView *callTypeImageView = [[UIImageView alloc] initWithFrame:callTypeImageFrame];
callTypeImageView.image = callTypeImage;
[callView addSubview:callTypeImageView];
selectionView = [[UIView alloc] initWithFrame:CGRectMake(10, 7, 200, 65)];
[selectionView setBackgroundColor: [UIColor clearColor]];
}
return self;
}
- (void)setImageType:(CallType)newImageType {
imageType = newImageType;
if (imageType == Fire) {
CGRect callTypeImageFrame = CGRectMake(275, 37, 18, 18);
UIImageView *callTypeImageView = [[UIImageView alloc] initWithFrame:callTypeImageFrame];
callTypeImageView.image = [UIImage imageNamed:#"red.png"];
[callView addSubview:callTypeImageView];
}
else if (imageType == EMS) {
CGRect callTypeImageFrame = CGRectMake(275, 37, 18, 18);
UIImageView *callTypeImageView = [[UIImageView alloc] initWithFrame:callTypeImageFrame];
callTypeImageView.image = [UIImage imageNamed:#"yellow.png"];
[callView addSubview:callTypeImageView];
}
}
- (void)setImageType1:(County)newImageType1 {
imageType1 = newImageType1;
if (imageType1 == Washington) {
CGRect callTypeImageFrame = CGRectMake(275, 10, 18, 18);
UIImageView *countyImageView = [[UIImageView alloc] initWithFrame:callTypeImageFrame];
countyImageView.image = [UIImage imageNamed:#"blue.png"];
[callView addSubview:countyImageView];
}
else if (imageType1 == Clackamas) {
CGRect callTypeImageFrame = CGRectMake(275, 10, 18, 18);
UIImageView *countyImageView = [[UIImageView alloc] initWithFrame:callTypeImageFrame];
countyImageView.image = [UIImage imageNamed:#"green.png"];
[callView addSubview:countyImageView];
}
}
This is a little subtle, but the main area your code will hang on is in the setImageType: method.
You're adding a programmatically created Image View into your view hierarchy here:
UIImageView *callTypeImageView = [[UIImageView alloc] initWithFrame:callTypeImageFrame];
callTypeImageView.image = [UIImage imageNamed:#"red.png"];
[callView addSubview:callTypeImageView];
But you never actually remove the old image view. A better way to do this might be to cache the created image view in a property of the cell, then when you set the image type, send the message -[UIView removeFromSuperview] to the old image view before creating a new one.
As your code stands now, every time a cell is dequeued, a new image view is added to it, so every time the user scrolls up and down the table view, a new image view is created and added to the cell. It won't take long for there to be dozens of image views in each cell. I suspect this is causing many times more drawRect calls into image views than is actually necessary to achieve your purpose.
A better way of doing this would be to have both types of image views as properties that you create in the cell's init method, which are only configured in the setType methods. That way you only create one image view per type, and simply set configure its image in the appropriate setType method. Doing it this way, do bear in mind that removeFromSuperview will release the imageview, so you'll have to declare it as a strong property (assuming you're using ARC).
I appreciate neither of these solutions has anything to do with Grand Central Dispatch, but hopefully that should solve your problem without using a sledgehammer to crack a nut :).

Slow loading tableview on iPhone with reusable cells

I load the data from Parse.com backend, they send me a solutions for use the reusable cells but now I still have troubles with the loading speed, this is the coding I have in my tableview and I have a Subclass for making up my cells (ExploreStreamCustomCell.m)
- (ExploreStreamCustomCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
object:(PFObject *)object
{
static NSString *CellIdentifier = #"ExploreStreamCustomCell";
ExploreStreamCustomCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[ExploreStreamCustomCell alloc] initWithStyle:UITableViewCellStyleSubtitle
reuseIdentifier:CellIdentifier];
}
// Configure the cell
cell.listItemTitle.text = [object objectForKey:#"text"];
cell.checkinsLabel.text = [NSString stringWithFormat:#"%#", [object objectForKey:#"checkins"]];
cell.descriptionLabel.text = [object objectForKey:#"description"];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
PFFile *listThumbnail = [object objectForKey:#"header"];
cell.listViewImage.image = [UIImage imageNamed:#"loading_image_stream.png"]; // placeholder image
cell.listViewImage.file = listThumbnail;
[cell.listViewImage loadInBackground:NULL];
return cell;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForNextPageAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [super tableView:tableView cellForNextPageAtIndexPath:indexPath];
cell.textLabel.font = [cell.textLabel.font fontWithSize:kPAWWallPostTableViewFontSize];
return cell;
}
If I have all the content of the //configure cell in the cell == nil the it's fast but it show up 3 of the 9 unique datarows and repeat those 3 unique content cell 3 times?
Edit extra code within ExploreStreamCustomCell.m
#import "ExploreStreamCustomCell.h"
#implementation ExploreStreamCustomCell
#synthesize listViewImage,
iconLocation,
iconPeople,
iconCheckins,
listItemTitle,
locationLabel,
peopleLabel,
checkinsLabel,
descriptionLabel,
listItemView;
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
if(self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]){
//Initialization code
listItemView = [[UIView alloc] init];
listViewImage = [[PFImageView alloc] init];
iconLocation = [[UIImageView alloc] init];
iconPeople = [[UIImageView alloc] init];
iconCheckins = [[UIImageView alloc] init];
listItemTitle = [[UILabel alloc] init];
locationLabel = [[UILabel alloc] init];
peopleLabel = [[UILabel alloc] init];
checkinsLabel = [[UILabel alloc] init];
descriptionLabel = [[UILabel alloc] init];
listViewImage.image = [UIImage imageNamed:#"nachtwacht_list_formaat.png"];
iconLocation.image = [UIImage imageNamed:#"icon_magenta_location.png"];
iconPeople.image = [UIImage imageNamed:#"icon_magenta_people.png"];
iconCheckins.image = [UIImage imageNamed:#"icon_magenta_checkins.png"];
listItemTitle.text = #"text";
locationLabel.text = #"0,7 km";
peopleLabel.text = #"34";
checkinsLabel.text = #"61";
descriptionLabel.text = #"Description text.";
[self.contentView addSubview:listItemView];
[self.contentView addSubview:listViewImage];
[self.contentView addSubview:iconLocation];
[self.contentView addSubview:iconPeople];
[self.contentView addSubview:iconCheckins];
[self.contentView addSubview:listItemTitle];
[self.contentView addSubview:locationLabel];
[self.contentView addSubview:peopleLabel];
[self.contentView addSubview:checkinsLabel];
[self.contentView addSubview:descriptionLabel];
}
return self;
}
- (void)layoutSubviews {
[super layoutSubviews];
CGRect contentRect = self.contentView.bounds;
CGFloat boundsX = contentRect.origin.x;
CGRect frame;
frame= CGRectMake(boundsX+0 , 33, 280, 124);
listViewImage.frame = frame;
listViewImage.contentMode = UIViewContentModeScaleAspectFill;
listViewImage.layer.masksToBounds = YES;
//listViewImage.backgroundColor = [UIColor lightGrayColor];
frame= CGRectMake(boundsX+20 , 164, 12, 18);
iconLocation.frame = frame;
//iconLocation.backgroundColor = [UIColor lightGrayColor];
frame= CGRectMake(boundsX+102 , 164, 24, 18);
iconPeople.frame = frame;
//iconPeople.backgroundColor = [UIColor lightGrayColor];
frame= CGRectMake(boundsX+193 , 164, 20, 16);
iconCheckins.frame = frame;
//iconLocation.backgroundColor = [UIColor lightGrayColor];
frame= CGRectMake(boundsX+0 , 0, 280, 33);
listItemView.frame = frame;
listItemView.backgroundColor = [UIColor colorWithRed:0.749 green:0.000 blue:0.243 alpha:1.000];
frame= CGRectMake(boundsX+20 , 3, 240, 29);
listItemTitle.frame = frame;
//listItemTitle.textColor = [UIColor colorWithRed:250.0f/255.0f green:194.0f/255.0f blue:9.0f/255.0f alpha:0.8f];
listItemTitle.textAlignment = UITextAlignmentLeft;
listItemTitle.font = [UIFont boldSystemFontOfSize:15];
listItemTitle.textColor = [UIColor whiteColor];
listItemTitle.backgroundColor = [UIColor clearColor];
listItemTitle.lineBreakMode = UILineBreakModeTailTruncation;
//listItemTitle.backgroundColor = [UIColor orangeColor];
frame= CGRectMake(boundsX+40 , 164, 57, 21);
locationLabel.frame = frame;
locationLabel.textAlignment = UITextAlignmentLeft;
locationLabel.font = [UIFont boldSystemFontOfSize:12];
locationLabel.textColor = [UIColor colorWithRed:0.749 green:0.000 blue:0.243 alpha:1.000];
locationLabel.backgroundColor = [UIColor clearColor];
locationLabel.lineBreakMode = UILineBreakModeTailTruncation;
locationLabel.numberOfLines = 1;
//locationLabel.backgroundColor = [UIColor redColor];
frame= CGRectMake(boundsX+134 , 164, 57, 21);
peopleLabel.frame = frame;
peopleLabel.textAlignment = UITextAlignmentLeft;
peopleLabel.font = [UIFont boldSystemFontOfSize:12];
peopleLabel.textColor = [UIColor colorWithRed:0.749 green:0.000 blue:0.243 alpha:1.000];
peopleLabel.backgroundColor = [UIColor clearColor];
peopleLabel.lineBreakMode = UILineBreakModeTailTruncation;
peopleLabel.numberOfLines = 1;
frame= CGRectMake(boundsX+221 , 164, 51, 21);
checkinsLabel.frame = frame;
checkinsLabel.textAlignment = UITextAlignmentLeft;
checkinsLabel.font = [UIFont boldSystemFontOfSize:12];
checkinsLabel.textColor = [UIColor colorWithRed:0.749 green:0.000 blue:0.243 alpha:1.000];
checkinsLabel.backgroundColor = [UIColor clearColor];
checkinsLabel.lineBreakMode = UILineBreakModeTailTruncation;
checkinsLabel.numberOfLines = 1;
frame= CGRectMake(boundsX+0 , 189, 280, 55);
descriptionLabel.frame = frame;
descriptionLabel.textAlignment = UITextAlignmentLeft;
descriptionLabel.font = [UIFont systemFontOfSize:13];
descriptionLabel.backgroundColor = [UIColor clearColor];
descriptionLabel.lineBreakMode = UILineBreakModeTailTruncation;
descriptionLabel.numberOfLines = 3;
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated];
// Configure the view for the selected state
}
/*
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
}
return self;
}
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect
{
// Drawing code
}
*/
#end
A great way to explore the inefficiencies of your code is to use Instruments' Time Profiler tool. The Time Profiler will let you see how much time is being spent on each task, line-by-line in your code.
I would recommend the following settings for profiling:
From Apple's Face Detection sample app:
You can then double click any line (higher percentages mean more time is being devoted to that method call) to see in the code how much time is spent in each place.
From here you can begin to figure out where you are being inefficient and see exactly what is taking up so much time. Good luck!

Resources