Custom UITableViewCell using xib - ios

I have a custom UITableViewCell which links to a UITableVIewCell xib. When I run the app, I get an error.
I did a lot of searching and I came up with this. When I try dragging from the cells view to the file owner, it seems like the view is not clickable, or drag-able.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"CategorieUITableVIewCell"];
if (cell == nil) {
UIViewController *tempVC = [[UIViewController alloc] initWithNibName:#"CategorieUITableVIewCell" bundle:nil];
cell = (CategorieUITableVIewCell *)tempVC.view;
}
return cell;
}
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '-[UIViewController _loadViewFromNibNamed:bundle:] loaded the "CategorieUITableVIewCell" nib but the view outlet was not set.'
Not sure if this is clear enough, but if you have any questions, please ask.

This will work for SURE. You can try this in cellForRowAtIndexPath method.
static NSString *categoryTableIdentifier = #"CategoryUITableViewCell";
CategoryUITableViewCell *cell = (CategoryUITableViewCell *)[tableView dequeueReusableCellWithIdentifier: categoryTableIdentifier];
if (cell == nil)
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"CategoryUITableViewCell" owner:self options:nil];
cell = [nib objectAtIndex:0];
}
cell.CustomedLabel.text=[YourArray objectAtIndex:indexPath.row];
return cell;
And IMPORTANT thing to note is in your Custom cell class you will have to connect the outlet to "Table View Cell" and not the "File's Owner" when you are working with Custom Cell

Please check the identifier matches with the one you specified in your xib. And then just replace your
if (cell == nil) {
UIViewController *tempVC = [[UIViewController alloc] initWithNibName:#"CategorieUITableVIewCell" bundle:nil];
cell = (CategorieUITableVIewCell *)tempVC.view;
}
code to
if (cell == nil) {
cell = [[[NSBundle mainBundle] loadNibNamed:#"CategorieUITableVIewCell" owner:nil options:nil] objectAtIndex:0];
}

Check cell identifier and class name in xib.

Related

Register nib for multiple UITableViewCells in a same .Xib file

I have created a .xib file which has more than 2 tableview cells. I used the following code in the viewDidLoad() method for registering nib to reuse cells.
UINib *nib = [UINib nibWithNibName:#"CartTableViewCells" bundle:nil];
[self.tableView registerNib:nib forCellReuseIdentifier:#"Cell0"];
[self.tableView registerNib:nib forCellReuseIdentifier:#"Cell1"];
[self.tableView registerNib:nib forCellReuseIdentifier:#"Cell2"];
And In - [UITableView CellForRowAtIndexPath] method, I used the following code.
cell0 = (CartTableViewCells *)[self.tableView dequeueReusableCellWithIdentifier:#"Cell0"];
if (cell0==nil)
{
cell0 = [[[NSBundle mainBundle] loadNibNamed:#"CartTableViewCells" owner:self options:nil] objectAtIndex:0];
}
But My app crashed with the following error:
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'invalid nib registered for identifier (Cell0) - nib must contain exactly one top level object which must be a UITableViewCell instance'
You can do this, provided you have some way of distinguishing the views in your XIB (tags, custom classes, etc). You don't even need to register the nib – all you have to do is this:
- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSInteger cellIndex = 12345;
NSString *cellIdentifier = #"MyAwesomeCell";
// dequeue cell or, if it doesn't exist yet, create a new one from the nib
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (!cell)
{
NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:#"MyNibWithLotsOfCustomCells" owner:self options:nil];
NSUInteger index = [topLevelObjects indexOfObjectPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) {
// if you distinguish the views by class
return [obj isMemberOfClass:NSClassFromString(cellIdentifier)];
// if you distinguish the views by tag
return [(UIView*)obj tag] == cellIndex;
}];
cell = topLevelObjects[index];
}
// etc.
}
It's important to use dequeueReusableCellWithIdentifier: and not dequeueReusableVellWithIdentifier:forIndexPath: (the difference is explained in this thread).

Empty prototype cell for a UITableView

I have a new project where I had to drag a prototype cell to a existing table view. I then
added some labels to the prototype cell with appropriate tags
set a identifier for the cell
and then in my tableview delegate when I get the delegate callback :
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"myCustomCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
// Configure the cell...
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
UILabel *nameLabel = (UILabel *)[cell viewWithTag:11];
I see that nameLabel is nil. I have double checked and tripled checked the tag and reusable identifier with no luck. In the storyboard, I see that the tableview has the pro type cell as its cell with the contentView showing my labels. What am I missing?
Do you ever create a new cell in the if (cell == nil) branch? If yes, you are creating a regular UITAbleViewCell there. Do not expect any custom lable there, because you don't load it from any nib file nor from the storyboard.
Of what type is the cell object? NSLog it or have a look in the debugger which type is actually created.
You are allocating UITableViewCell which don't contain your custom label. If you have created a View using Storyboard then you should allocate that view using following method.
You can create a Utility method to get Class instance from NibName
+ (id)loadNibNamed:(NSString *)nibName ofClass:(Class)objClass
{
if (nibName && objClass)
{
NSArray *objects = [[NSBundle mainBundle] loadNibNamed:nibName
owner:nil
options:nil];
for (id currentObject in objects )
{
if ([currentObject isKindOfClass:objClass])
return currentObject;
}
}
return nil;
}
Use this in your code like
CustomViewCell *cell = (CustomViewCell *)[tableView dequeueReusableCellWithIdentifier:#"CustomViewCell"];
if (cell == nil)
{
cell = [Utility loadNibNamed:#"CustomViewCell" ofClass:[CustomViewCell class]];
}
cell.yourLabel.text = #"Dummy Text";
Hopefully this will help you.

iOS: UITableViewCell subclassing with nib, into UIView (not view controller) subclass

I have a custom UIView subclass Leaderboard which itself contains a tableview tblLeaderboard. The interface was created with a xib. Additionally, I have a UITableViewCell subclass LeaderboardCell which also has a xib. I'm having trouble registering the cell in the tableview.
Here's what I tried, first I registered the nib with the tableview:
-(id)initWithCoder:(NSCoder *)aDecoder
{
self = [super initWithCoder:aDecoder];
if (self)
{
leaderInfo = [NSMutableArray array];
tblLeaderboard.dataSource=self;
[tblLeaderboard registerNib:[UINib nibWithNibName:#"LeaderboardCell" bundle:[NSBundle mainBundle]] forCellReuseIdentifier:#"leaderboardCell"];
}
return self;
}
Then when initializing the cell I have:
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"leaderboardCell";
LeaderboardCell *cell = [tableView
dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[LeaderboardCell alloc]
initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:CellIdentifier];
}
//ADDED THIS IN CASE DEFAULT CELL WAS LOADED
cell.textLabel.text = [[leaderInfo objectAtIndex:indexPath.row] objectForKey:#"name" ];
cell.name.text = [[leaderInfo objectAtIndex:indexPath.row] objectForKey:#"name"];
cell.score.text = [[[leaderInfo objectAtIndex:indexPath.row] objectForKey:#"score"] stringValue];
return cell;
}
The cell doesn't load the nib. It just makes a custom cell (the default cell loads the name and score properly, so I know the datasource is working fine).
I'm not sure if I'm getting in trouble here for using a UIView and not a ViewController to control my UITableView?
I don't really have alot of experiences with xibs, but in my old project I did it this way:
static NSString *leaderBoardIdentifier = #"leaderboardCell"; //cell identifier same name as identifier in xib cell's attribute inspector
LeaderboardCell *cell = (LeaderboardCell *)[tableView dequeueReusableCellWithIdentifier:leaderBoardIdentifier];
if (cell == nil)
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:leaderBoardIdentifier owner:self options:nil];
cell = [nib objectAtIndex:0];
}
I have my cell's xib file with h/m files. In my .h I've just connected elements from xib.
initWithStyle and setSelected methods in cell class have default code in them.

Getting EXC_Bad_Access while scrolling tableview

I am getting EXC_BadAccess error message while i am scrolling tableview.
the following is the code i have done in cellForRowAtIndexPath.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier=#"customCellHistory";
customCellHistory *cell=(customCellHistory*)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
NSArray *topLevelObjects=[[NSBundle mainBundle]loadNibNamed:#"customCellHistory" owner:self options:nil];
for (id currentObject in topLevelObjects) {
if ([currentObject isKindOfClass:[UITableViewCell class]] ) {
cell=(customCellHistory*)currentObject;
break;
}
}
}
cell.lb11.text=[cellArray1 objectAtIndex:indexpath.row];
cell.lbl2.text=[cellArray2 objectAtIndex:indexpath.row];
return cell;
}
I can sense the problem is arising due to some mistake in the above code.
I used CustomCell in the above code to display a customized cell.
can anyone tell me what wrong have i done in this code
Hey try the following code, dont forget to set the cell identifier in you custom XIB to customCellHistory
At the top
#import "customeCellHistory.h"
then
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *cellIdentifier = #"customCellHistory";
customCellHistory *cell = (customCellHistory *)[tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) {
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"customCellHistory" owner:self options:nil];
cell = [nib objectAtIndex:0];
}
cell.lb11.text=[cellArray1 objectAtIndex:indexpath.row];
cell.lbl2.text=[cellArray2 objectAtIndex:indexpath.row];
return cell;
}
The problem seems to arise from the strange loop you have. Use the last object method to set cell from the nib.
You are reusing a cell and then changing the cell in your loop which probably leads to a cell not existing where you are looking.
if (cell == nil) {
NSArray *topLevelObjects=[[NSBundle mainBundle]loadNibNamed:#"customCellHistory" owner:self options:nil];
You don't need that code. Just register the nib with the table view, earlier on:
[self.tableView registerNib:[UINib nibWithNibName:#"customCellHistory" bundle:nil]
forCellReuseIdentifier:#"customCellHistory"];
Now when you call dequeueReusableCellWithIdentifier, the nib will be loaded and the cell will be delivered, if there is no spare cell in the reuse pile. This ensures that you consistently have a cell and that it is the right kind of cell. Use the methods the framework gives you.

How to load xib file for cell in tableview in iphone

I saw there are lots of resources available on net regarding this question. I have to load a different XIB (UIViewContoller) file for my cell. I have designed my cell looks there and I want to load that design in my cell.
I wrote this code but I am getting an exception.
-[UIView setTableViewStyle:]: unrecognized selector sent to instance 0x6040de0
2011-07-11 14:42:27.461 TableViewTest[2776:207] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[UIView setTableViewStyle:]: unrecognized selector sent to instance 0x6040de0'
And here is my code of loading nib file
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
// Load the top-level objects from the custom cell XIB.
NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:#"loadXibfile" owner:self options:nil];
// Grab a pointer to the first object (presumably the custom cell, as that's all the XIB should contain).
cell = [topLevelObjects objectAtIndex:0];
}
return cell;
You should use UITableViewCell and not UIView in your XIB file.
Here is the solution and it is useful for me and home for you or some else may be.
cell = [[[YourCustomcell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:#"cell"] autorelease];
NSArray *toplavelobject=[[NSBundle mainBundle]loadNibNamed:#"YourCustomcell" owner:self options:nil];
for(id c in toplavelobject)
{
if ([c isKindOfClass:[UITableViewCell class]])
{
cell=(YourCustomcell *) c;
break;
}
}
Though not a direct answer to your issue, I recommend you make use of this UITableViewCellFactory class, it's very convenient:
http://blog.carbonfive.com/2009/07/16/loading-uitableviewcells-from-a-nib-file/
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
NSString *CellIdentifier = [NSString stringWithFormat:#"Cell%d",indexPath.row];
LatestNewsCell *cell = (LatestNewsCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[NSBundle mainBundle] loadNibNamed:#"LatestNewsCell" owner:self options:nil] objectAtIndex:0];
}
}
This is what I did. Again some of the technique is quite awkward and I need improvement.
First I created a new subclass of UITableViewCell. The problem is I do not get an option to check "include" xib. It's as if xib is meant only for UIViewcontroller. I suppose you can create a subclass of UIViewController with XIB and then crate another subclass of UITableViewCell and move the template to your subclass of UIViewController.
Works.
Then I put these function:
#implementation BGCRBusinessForDisplay2
- (NSString *) reuseIdentifier {
return [[self class] reuseIdentifier];
};
+ (NSString *) reuseIdentifier {
return NSStringFromClass([self class]);
};
To initialize I do:
- (BGCRBusinessForDisplay2 *) initWithBiz: (Business *) biz
{
if (self.biz == nil) //First time set up
{
self = [super init]; //If use dequeueReusableCellWithIdentifier then I shouldn't change the address self points to right
NSString * className = NSStringFromClass([self class]);
PO (className);
[[NSBundle mainBundle] loadNibNamed:className owner:self options:nil];
[self addSubview:self.view]; //What is this for? self.view is of type BGCRBusinessForDisplay2. That view should be self, not one of it's subview Things don't work without it though
}
if (biz==nil)
{
return self; //Useful if we only want to know the height of the cell
}
self.biz = biz;
self.Title.text = biz.Title; //Let's set this one thing first
self.Address.text=biz.ShortenedAddress;
The [self addSubview:self.view]; is kind of awkward. It's what other says I should do and it won't work without it. Actually I want self.view to be self, rather than a subView of self. But hei.... Don't know how to do it otherwise.
...
Then I implement this for cellForRowAtIndexPath
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
//[FetchClass singleton].FetchController
if([BGMDCRFetchClass singleton].FetchController.fetchedObjects.count!=0){
BGCRBusinessForDisplay2 *cell = (BGCRBusinessForDisplay2*)[tableView dequeueReusableCellWithIdentifier:[BGCRBusinessForDisplay2 reuseIdentifier]];
if (cell == nil)
{
cell =[BGCRBusinessForDisplay2 alloc];
}
else{
while (false);
}
Business * theBiz=[[BGMDCRFetchClass singleton].FetchController objectAtIndexPath:indexPath];
cell = [cell initWithBiz:theBiz];
return cell;
//return theBiz.CustomCell;
}else{
UITableViewCell * tvc=[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"tvc"];
return tvc;
}
}
Notice that I separate alloc from init. That's kind of awkward. That is why in my - (BGCRBusinessForDisplay2 *) initWithBiz: (Business *) biz if a cell has been initialized before, I simply don't do the upper part of the init. I simply assign values of Business * to the various outlet in the BGCRBusinessForDisplay2.
I someone can improve my answers they are welcome. So far it works.

Resources