Custom UITableViewCell using storyboard and subclass - ios

I have created a subclass of UITableViewCell and I called it DCCustomCell. This is the DCCustomCell.h file.
#import <UIKit/UIKit.h>
#interface DCCustomCell : UITableViewCell
#property (weak, nonatomic) IBOutlet UIImageView *imageView;
#property (weak, nonatomic) IBOutlet UILabel *title;
#property (weak, nonatomic) IBOutlet UILabel *date;
#property (weak, nonatomic) IBOutlet UILabel *price;
#end
All the proprieties are correcty connected with elements in my iPhone.storyboard file.
I also selected the tableViewCell in iPhone.storyboard and i setted my cell's identifier to "CustomCell" and the class to DCCustomCell.
This is the UITableViewController's viewDidLoad method:
- (void)viewDidLoad
{
[super viewDidLoad];
self.tableView.delegate = self;
self.tableView.dataSource = self;
[self.tableView registerClass:[DCCustomCell class] forCellReuseIdentifier:#"CustomCell"];
// Do any additional setup after loading the view, typically from a nib.
}
and this is the tableView:cellForRowAtIndexPath: method:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *identifier = #"CustomCell";
DCCustomCell *cell = (DCCustomCell *)[tableView dequeueReusableCellWithIdentifier:identifier];
NSLog(#"%#" ,cell);
cell.imageView.image = [UIImage imageNamed:#"info_button.png"];
cell.title.text = #"Hello!";
cell.date.text = #"21/12/2013";
cell.price.text = #"€15.00";
return cell;
}
The problem is that the imageView is correctly setted, but all the labels are blank. If I change the imageView property name to, for example, eventImageView, the image will not be setted.
This is the result:
I can't figure out how I can solve this problem.
EDIT: if I remove
[self.tableView registerClass:[DCCustomCell class] forCellReuseIdentifier:#"CustomCell"];
from viewDidLoad all seems to work. why?

As you noticed it works when you remove
[self.tableView registerClass:[DCCustomCell class] forCellReuseIdentifier:#"CustomCell"];
You only have to do this if you use dequeueReusableCellWithIdentifier:indexPath: AND have not already set the custom class in the identity inspector for that cell. If you use registerClass: forCellReuseIdentifier the cell will be initialized with initWithStyle:reuseIdentifier: instead of initWithCoder: thus screwing up your connections you made in the storyboard.

Have you bind the Controls to IBOutlet ?
You can try setting DCCustomCell to UITableviewCell's class directly in Storyboard.
And than you need to set outlets with controls in cell

Try:
if (cell == null) {
//create and initialize cell
}
after
DCCustomCell *cell = (DCCustomCell *)[tableView dequeueReusableCellWithIdentifier:identifier];

You first check your outlets properly that all the labels are connected & write this also :
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *identifier = #"CustomCell";
DCCustomCell *cell = (DCCustomCell *)[tableView dequeueReusableCellWithIdentifier:identifier];
if (cell == nil)
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"DCCustomCell" owner:self options:nil];
cell = [nib objectAtIndex:0];
}
NSLog(#"%#" ,cell);
cell.imageView.image = [UIImage imageNamed:#"info_button.png"];
cell.title.text = #"Hello!";
cell.date.text = #"21/12/2013";
cell.price.text = #"€15.00";
return cell;
}

Related

Crash when creating custom UITableViewCell

I am trying to create a custom table view cell with a xib but when I call:
CustomReferenceTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
I get the following:
Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<NSObject 0x7aa59c00> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key
Here is my setup:
- (void)viewWillAppear:(BOOL)animated
{
[self.tableView registerNib:[UINib nibWithNibName:#"CustomReferenceTableViewCell"
bundle:[NSBundle mainBundle]]
forCellReuseIdentifier:#"referenceCell"];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = #"referenceCell";
CustomReferenceTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) {
cell = [[CustomReferenceTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
}
cell.number.text = #"1";
cell.referenceName.text = #"Name";
cell.reference.text = #"The text of the reference";
return cell;
}
Here is a picture of my connections in interface builder. Also my cellIdentifiers match between class and xib:
I have seen this post here but I still can't seem to get it work.
Help would be greatly appreciated.
Edit
Here is a pic showing setting of custom class. Below that is my initialiser for the tableViewCell:
Here is the header:
#import <UIKit/UIKit.h>
#interface CustomReferenceTableViewCell : UITableViewCell
#property (nonatomic, weak) IBOutlet UILabel *number;
#property (nonatomic, weak) IBOutlet UILabel *referenceName;
#property (nonatomic, weak) IBOutlet UILabel *reference;
#end
And here is the implementation:
#import "CustomReferenceTableViewCell.h"
#implementation CustomReferenceTableViewCell
- (void)awakeFromNib {
// Initialization code
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated];
// Configure the view for the selected state
}
#end
I think you are setting the file owner of the cell to your custom cell which you shouldn't do. The way to get things working for a custom cell is,
In your xib, have a Table View Cell component an populate the contents of the cell in its ContentView.
Make your class CustomReferenceTableViewCell as the Custom Class of that cell component.
Now, do NOT register the cell in your tableview; instead do the following in the cellForRowAtIndexPath when your cell is nil after [tableView dequeueReusableCellWithIdentifier:cellIdentifier]; and then register it:
cell = [self.tableView dequeueReusableCellWithIdentifier:cellID];
if(cell == nil) {
[self.tableView registerNib:[UINib nibWithNibName:[#"CustomReferenceTableViewCell" ] bundle:nil] forCellReuseIdentifier:cellID];
NSArray *nibContents;
CustomReferenceTableViewCell *cell;
nibContents = [[NSBundle mainBundle]
loadNibNamed:nibName owner:self options:NULL];
NSEnumerator *nibEnumerator = [nibContents objectEnumerator];
NSObject *nibItem = nil;
while ((nibItem = [nibEnumerator nextObject]) != nil) {
if ([nibItem isKindOfClass:[CustomReferenceTableViewCell class]]) {
cell = (CustomReferenceTableViewCell *)nibItem;
}
}
}
This method has been working out for me for the past 8 months. I have no reasons why it could cause a problem to you.
Try to set your static NSString *cellIdentifier = #"referenceCell"; above #interface
And change registerNib place from WillAppear to viewDidLoad. Also you can change cell creating
CustomReferenceTableViewCell *cell = (CustomReferenceTableViewCell *)[tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) {
cell = [[[NSBundle mainBundle]loadNibNamed:#"CustomReferenceTableViewCell" owner:self options:nil] lastObject];
}
Just follow my coding for your app
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
CustomCell *cell = (CustomCell *)[tableView dequeueReusableCellWithIdentifier:#"Reuse"];
NSArray *nib=[[NSBundle mainBundle] loadNibNamed:#"CustomCell" owner:self options:nil];
if(cell == nil)
{
cell = [nib objectAtIndex:0];
}
cell.number.text = #"1";
cell.referenceName.text = #"Name";
cell.reference.text = #"The text of the reference";
return cell;
}
Firstly CodingVoldermort's answer helped me get to sort out the issue. I was setting the File's Owner to my custom class which you shouldn't do. This should be left as NSObject.
The reason I thought it needed to be changed was because I couldn't hook up my IBOutlets by holding control and clicking on the tableview image under placeholders and dragging to the appropriate view in the xib.
Instead I needed to go under 'Show the connection inspector' pane and control + click and drag from there to get the connections to work. Then my original posted code would work.
Many thanks for all the responses guys.

changing a customlabel within an expanding UItableviewcell

I created a custom table cell that expands. When it expands, it shows a UILabel along with two UIButtons. The UILabel should show data from the backend. I created the customLabel in the CustomCell interface file. Then I imported the CustomCell class into my InboxTableViewController, and implemented the custom cell. The label only appears when the cell is tapped, and expands. How would I go about changing the UILabel, because cell.customLabel.text, would not work here, since it is not a property of the cell. Here is the associated code:
CustomCell.h
#interface CustomCell : UITableViewCell
{
UIImage *userImage;
UILabel *userName;
//below widgets will display when user tapped
#public
UIButton *leftButton, *rightButton;
UILabel *customLabel;
BOOL userTapped;
}
#property (weak, nonatomic) IBOutlet UILabel *userName;
#property (weak, nonatomic) IBOutlet UIImageView *userImage;
- (void) setData:(NSDictionary*) d;
#end
and here is the inboxviewcontroller.m where i try to implement the customcell along with the customLabel.
:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
CustomCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
if (!cell) {
cell = [[CustomCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
cell.selectionStyle = UITableViewCellSelectionStyleNone;
// PFObject *message = [self.messages objectAtIndex:indexPath.row];
PFObject *message = [self.messages objectAtIndex:indexPath.row];
cell.userName.text = [message objectForKey:#"from"];
//cell.userImage.image = [message objectForKey:#"image1"];
cell.customLabel.text = [message objectForKey:#"message"];
return cell;}
This will not work as you are creating instance of CustomCell directly instead you have to load CustomCell view from nib so it will create instance of customLabel and using this you can set text, use below code
CustomCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
if (cell == nil) {
NSArray *nib=[[NSBundle mainBundle]loadNibNamed:#"CustomCell" owner:self options:nil];
cell=[nib objectAtIndex:0];
}
For custom UITableViewCell's you should take a look at this tutorial . It will give you the idea.

ios7 Storybaoard UITableViewCell not applying to table

I am adding a custom UITableViewCell to a UITableView in storyboard - via the prototype cell and a class file. When run, the row height is correct, but the content is still using the default with cell.textLabel.text, not my [cell.horseName setText:#"string"] setting.From reading the other posts on StackOverflow I've added:
RankingsTableViewController.m:viewDidLoad:
[self.tableView registerClass:[RankingTableViewCell class]
forCellReuseIdentifier:#"raceRankingCell"];
And also tried replacing:
RankingTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
with:
RankingTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[RankingTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
With no effect.
Here is what the storyboard looks like for the table:
From the tree view, you can see the Cell Identifier is raceRankingCell, in the Connections inspector, they are all hooked up to the class file:
Code:
RankingTableViewCell.h
#import <UIKit/UIKit.h>
#interface RankingTableViewCell : UITableViewCell
#property (weak, nonatomic) IBOutlet UILabel *raceLabel;
#property (weak, nonatomic) IBOutlet UILabel *horseNameLabel;
#property (weak, nonatomic) IBOutlet UILabel *jockeyLabel;
#property (weak, nonatomic) IBOutlet UILabel *rankingLabel;
#property (weak, nonatomic) IBOutlet UILabel *programIdLabel;
#property (weak, nonatomic) IBOutlet UIImageView *horseImage;
#end
RankingTableViewController.m
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"raceRankingCell";
RankingTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
/* Test#1- no change in behavior
RankingTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[RankingTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
*/
// Any data yet? If not, show the no data yet cell
if([_raceResultsArray count] < 1) {
DLog(#"No race results yet");
[cell.horseNameLabel setText:#"Data is loading... - horseName"];
cell.textLabel.text = #"Data is loading... - textLabel";
When I use the line cell.textLabel.text = #"Data is loading... - textLabel"; the string is displayed.
What am I missing?
When a cell is defined in a storyboard, you shouldn't register the class. Registering a class means the table view will get the cell (including all its subviews) from the class implementation, so it should only be used when you've defined the cell wholly in code (no xib or storyboard). Deleting that line should fix your problem.
Try this.
RankingTableViewCell *cell = (RankingTableViewCell*)[self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];

iOS UITableViewCell releasing subviews

I have noticed that UITableViewCell is not reusing it's subviews and seems to be released when scrolling up and down. I am creating UITableViewCell subview and animating it on viewDidAppear. I want to do this only once and then I expect subview to stay in the ContentView forever until view disappears. So I have done following which I think right way but not sure what's wrong; can someone help?
UINib *nib1 = [UINib nibWithNibName:#"CustomCell" bundle:nil];
[self.tableView registerNib:nib1 forCellReuseIdentifier:#"CustomCell"];
#interface CustomCell : UITableViewCell
#property (nonatomic) IBOutlet UILabel *title;
#property (nonatomic) CustomeView *customeView;
#end
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString cellIdentifier = #"CustomCell";
CustomCell *customCell = [tableView dequeueReusableCellWithIdentifier:accountCellIdentifier forIndexPath:indexPath];
......
customCell.customeView = (CustomeView*)[customCell.contentView viewWithTag:101];
if(!customCell.customeView) {
customCell.customeView = [CustomeView new];
//configure customview...
customCell.customeView.tag = 101;
[customCell.contentView addSubview:customCell.customeView];
}
return cell;
}
Try to change your property type to strong:
#property (strong, nonatomic) CustomeView *customeView;

Custom UITableCell not working

I searched too much, tried lot of thinks but i couldn't make it work.
I have a view controller, and in that controller i have a tableview which has custom cell.
I connect outlets,datasource and delegate but when i run the project, instead of my custom cells. UITableCell is shown and not showing data either. here is my .h and .m files
#import <UIKit/UIKit.h>
#class SelectMutantCell;
#interface MutantViewController : UIViewController <UITableViewDataSource,UITableViewDelegate>{
UITableView *tableView;
IBOutlet SelectMutantCell *mutantCell;
}
#property (nonatomic, weak) IBOutlet UITableView *tableView;
#property (nonatomic, weak) SelectMutantCell *mutantCell;
- (IBAction)cancel:(id)sender;
#end
and here is my .m file
#implementation MutantViewController
#synthesize tableView = _tableView;
#synthesize mutantCell = _mutantCell;
NSArray *mutants;
- (void)viewDidLoad
{
[super viewDidLoad];
//mutants = [mutants initWithObjects:#"Keko",#"HEHE",#"PEPE", nil];
UINib *cellNib = [UINib nibWithNibName:#"SelectMutantCell" bundle:nil];
[self.tableView registerNib:cellNib forCellReuseIdentifier:#"SelectMutantCell"];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *CellIdentifier = #"SelectMutantCell";
SelectMutantCell *cell = (SelectMutantCell *)[self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
NSLog(#"---");
cell.nameLabel.text = #"Hehe"];
cell.descriptionLabel.text = #"hhe";
return cell;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return 3;
}
the NSLog(#"---") is for debugging and it appears when running. the problem is in
cell.nameLabel.text = #"Hehe"];
cell.descriptionLabel.text = #"hhe";
this block, if i write cell.textLabel.text = "test" it works but i need my custom cell to shown.
any help will be appreciated..
Insert if(cell==nil){} loop
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *CellIdentifier = #"SelectMutantCell";
SelectMutantCell *cell = (SelectMutantCell *)[self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[SelectMutantCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
NSLog(#"---");
cell.nameLabel.text = #"Hehe"];
cell.descriptionLabel.text = #"hhe";
return cell;
}
Looking at your cellForRowAtIndexPath: method, you never initialize the cell. Try doing it like this:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *CellIdentifier = #"SelectMutantCell";
SelectMutantCell *cell = (SelectMutantCell *)[self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:#"SelectMutantCell" owner:nil options:nil];
for(id currentObject in topLevelObjects) {
if([currentObject isKindOfClass:[SelectMutantCell class]]) {
cell = (SelectMutantCell *)currentObject;
break;
}
}
}
NSLog(#"---");
cell.nameLabel.text = #"Hehe"];
cell.descriptionLabel.text = #"hhe";
return cell;
}
I had the same issue. To solve it check the followings :
in your nib file, you have removed the root view created by default, and dragged a UITableViewCell from XCode object browser, then set the custom type of the UItableViewCell to your subclass SelectMutantCell
you have linked the outlets
you have added the cell identifier to SelectMutantCell, as you would do in storyboard
last but not least, you didn't add the same cell in your storyboard TableView, it will conflit between the one from storyboard and the one from [self.tableView registerNib:cellNib forCellReuseIdentifier:#"SelectMutantCell"];

Resources