Multiple Custom Rows UITableView? - iphone

I've been searching a lot but didn't find anything useful related to multiple custom rows, I need to create a settings tableView for my app,in which I need to load the rows from xib files,like:
ROW 1 =>> XIB 1.
ROW 2 =>> XIB 2.
ROW 3 =>> XIB 3.
ROW 4 =>> XIB 4.
My present code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell=nil;
//We use CellType1 xib for certain rows
if(indexPath.row==0){
static NSString *CellIdentifier = #"ACell";
cell =(ACell*) [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(cell==nil){
NSArray *nib= [[NSBundle mainBundle] loadNibNamed:#"ACell" owner:self options:nil];
cell = (ACell *)[nib objectAtIndex:0];
}
//Custom cell with whatever
//[cell.customLabelA setText:#"myText"]
}
//We use CellType2 xib for other rows
else{
static NSString *CellIdentifier = #"BCell";
cell =(BCell*) [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(cell==nil){
NSArray *nib= [[NSBundle mainBundle] loadNibNamed:#"BCell" owner:self options:nil];
cell = (BCell *)[nib objectAtIndex:0];
}
//Custom cell with whatever
//[cell.customLabelB setText:#"myText"]
}
return cell;
}

First you create some custom UITableViewCell classes (.h and .m), as many as you have xib files:
So you could have CellType1 and CellType2 for example.
CellType1.h would look something like
#import <UIKit/UIKit.h>
#interface CellType1 : UITableViewCell
#property(nonatomic,strong) IBOutlet UILabel *customLabel;
#end
Then you create the xib files, you can use default view type, but then, just remove the view that is automatically created, replace that by a UITableViewCell, and change the class to CellType1. Do the same for CellType2.
Then in your tableViewController, write cellForRow like this:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell=nil;
//We use CellType1 xib for certain rows
if(indexPath.row==<whatever you want>){
static NSString *CellIdentifier = #"CellType1";
cell =(CellType1*) [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(cell==nil){
NSArray *nib= [[NSBundle mainBundle] loadNibNamed:#"CellType1" owner:self options:nil];
cell = (CellType1 *)[nib objectAtIndex:0];
}
//Custom cell with whatever
[cell.customLabel setText:#"myText"]
}
//We use CellType2 xib for other rows
else{
static NSString *CellIdentifier = #"CellType2";
cell =(CellType2*) [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(cell==nil){
NSArray *nib= [[NSBundle mainBundle] loadNibNamed:#"CellType2" owner:self options:nil];
cell = (CellType2 *)[nib objectAtIndex:0];
}
//Custom cell with whatever
[cell.customLabel setText:#"myText"]
}
return cell;
}

If you're not already familiar with loading a custom cell from a xib, check out the documentation here. To extend this to multiple custom xibs, you can create each table cell in a separate xib, give it a unique cell identifier, set the table view controller as the file's owner, and connect each cell to the custom cell outlet you define (in the docs, they use tvCell as this outlet). Then in your -tableView:cellForRowAtIndexPath: method, you can load the correct xib (or dequeue the correct reuseable cell) by checking which row you're providing a cell for. For example:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *MyIdentifier1 = #"MyIdentifier1";
static NSString *MyIdentifier2 = #"MyIdentifier2";
static NSString *MyIdentifier3 = #"MyIdentifier3";
static NSString *MyIdentifier4 = #"MyIdentifier4";
NSUInteger row = indexPath.row
UITableViewCell *cell = nil;
if (row == 0) {
cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifer1];
if (nil == cell) {
[[NSBundle mainBundle] loadNibNamed:#"MyTableCell1" owner:self options:nil];
cell = self.tvCell;
self.tvCell = nil;
}
}
else if (row == 1) {
cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifer2];
if (nil == cell) {
[[NSBundle mainBundle] loadNibNamed:#"MyTableCell2" owner:self options:nil];
cell = self.tvCell;
self.tvCell = nil;
}
}
else if (row == 2) {
cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifer3];
if (nil == cell) {
[[NSBundle mainBundle] loadNibNamed:#"MyTableCell3" owner:self options:nil];
cell = self.tvCell;
self.tvCell = nil;
}
}
else if (row == 4) {
cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifer4];
if (nil == cell) {
[[NSBundle mainBundle] loadNibNamed:#"MyTableCell4" owner:self options:nil];
cell = self.tvCell;
self.tvCell = nil;
}
}
// etc.
// Do any other custom set up for your cell
return cell;
}

Related

Scroll down crashes application on a UITableView with a custom UITableViewCell because of zombie object

I have this code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *simpleTableIdentifier = #"BSTGListCell";
BSTGListCell *cell = (BSTGListCell *)[tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil)
{
cell = [[[NSBundle mainBundle] loadNibNamed:#"BSTGListCell" owner:self options:nil] objectAtIndex:0];
}
PFObject* currentEl = [self.tableData objectAtIndex:indexPath.row];
cell.title.text = [currentEl objectForKey:#"Name"];
cell.description.text = [currentEl objectForKey:#"Address"];
return cell;
}
I am getting "message sent to deallocated instance" when scrolling down the table view which is added as a subview.
Zombie inspector says the accessed object is retained here:
cell = [[[NSBundle mainBundle] loadNibNamed:#"BSTGListCell" owner:self options:nil] objectAtIndex:0];
and probably released by ARC.
Why this happens and how I can prevent it?
You really shouldn't do it this way. The way to use cell from a nib is to register the nib, probably in viewDidLoad, like this:
UINib *nib = [UINib nibWithNibName:#"BSTGListCell" bundle:nil];
[self.tableView registerNib:nib forCellReuseIdentifier:#"BSTGListCell"];
Then in your cellForRowAtIndexPath, use dequeueReusableCellWithIdentifier:forIndexPath: and no if(cell == nil) clause.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
BSTGListCell *cell = (BSTGListCell *)[tableView dequeueReusableCellWithIdentifier:#"BSTGListCell" forIndexPath:indexPath];
PFObject* currentEl = [self.tableData objectAtIndex:indexPath.row];
cell.title.text = [currentEl objectForKey:#"Name"];
cell.description.text = [currentEl objectForKey:#"Address"];
return cell;
}
The actual problem with your code is that loadNibNamed:owner:options, returns an array, and you have to get the one object out of that array before you assign it to cell. But, the way I showed is a more efficient way to do this anyway.
My problem was something with the dequeueReusableCell line, i took it out like this link did and mine works now

how to solve NSInternalInconsistencyException?

I am getting an error when I try to show custom cell on my tableView. I have a nibFile connected with cells but I always get thread sigbart here
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"CellForOffers" owner:self options:nil];
I don't know why, and my cell for row at index implementation is
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"CellForOffers";
CellForOffers *cell =(CellForOffers *) [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"CellForOffers" owner:self options:nil];
cell = [nib objectAtIndex:0];
appDC * application = [dataArray objectAtIndex:[indexPath row]];
cell.namelbl.text=application.o_name;
cell.descriptionlbl.text=application.o_description;
[cell.imageView setImageWithURL:[NSURL URLWithString:application.o_image_url]];
}
return cell;
}
Add nib with its class like bellow...
cell = (CellForOffers *)[nib objectAtIndex:0];

Iphone : Use table custom cell

i'm using custom cell i learned in (This site). It's work in my old app but in this app i dont know why it's haven't work, when i run the above code he stuck with green error in line (NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:#"CustomCell" owner:self options:nil];).
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
CellIdentifier = #"CustomCell";
PCustomCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(cell == nil){
NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:#"CustomCell" owner:self options:nil];
for (id currentObject in topLevelObjects){
if ([currentObject isKindOfClass:[UITableViewCell class]]){
cell = (PCustomCell *) currentObject;
break;
}
}
}
P2Dict = [P2Rows objectAtIndex: indexPath.row];
cell.Contracts.text = [P2Dict objectForKey:#"Contracts"];
return cell;
}
http://ar2.co/SS2.png
custom cell xib .file take a tablecell.and in custom.m file implemented .and In view controller set the whole tableview through viewcontroller xib or programmatically .as ur choice .and set the delegate and datasourece methods.in datasource method written custom cell.code written below
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Custom";
CustomTableCell *cell = (CustomTableCell *) [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (!cell)
{
UINib *nib = [UINib nibWithNibName:#"CustomTableCell" bundle:nil];
NSArray *arr = [nib instantiateWithOwner:nil options:nil];
cell = [arr objectAtIndex:0];
}
cell.textLabel.text =[arr objectAtIndex:indexPath.row];
}
Did you have UITableviewCell(PCustomCell) at CustomCell.xib?
You should show screenshot of the error here. It's will be helpful.
Your error states: "Could not load NIB in bundle named "CustomCell"". So there lies your problem.... what is your xib named?
refer a following process. How to create a custom table cell is one kind of.
VocaTableCell is my case. make a your CustomTableCell.
#import <UIKit/UIKit.h>
#interface VocaTableCell : UITableViewCell
{
UILabel *vocaLabel;
}
#property (nonatomic, retain) IBOutlet UILabel *vocaLabel;
#end
#import "VocaTableCell.h"
#implementation VocaTableCell
#synthesize vocaLabel;
- (void)dealloc {
[vocaLabel release];
[super dealloc];
}
#end
Below code refer Befoe, Are you correctly make a customTableCell? below list check plz.
There are several ways to create about customTablecell.
My manner is very popular.
CustomTabelCell of File's Owner should be a NSObject.
(Very Important Default is Maybe UITableCell. You Must be a change File's Owner NSObject(NSObject mean is id type!))
CustomTableCell link a Object Class a your CustomTableCell Class.
Referencing Outlets link Not File's Owner, must be Your Directly link a CustomTableCell.
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Custom";
CustomTableCell *cell = (CustomTableCell *) [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (!cell)
{
UINib *nib = [UINib nibWithNibName:#"CustomTableCell" bundle:nil];
NSArray *arr = [nib instantiateWithOwner:nil options:nil];
cell = [arr objectAtIndex:0];
}
cell.textLabel.text =[arr objectAtIndex:indexPath.row];
}

request for member error when loading in customtableviewcell and setting its IBOUTLETS

I've spent the last 3 hours scratching my head at this issue because all seems correct, except I can't get through to my tableviewcell class to set the uilabels in my custom cell.
here is my code
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"TableViewCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"TableViewCell" owner:self options:nil];
cell = (UITableViewCell *)[nib objectAtIndex:0];
//cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:MyIdentifier] autorelease];
}
//cell.imageViewSection =
// Set up the cell
int storyIndex = [indexPath indexAtPosition: [indexPath length] - 1];
NSString *textTitle = [[stories objectAtIndex: storyIndex] objectForKey: #"title"];
NSURL *imageurl = [NSURL URLWithString:[[stories objectAtIndex: storyIndex] objectForKey: #"description"]];
UIImage *image = [UIImage imageWithData: [NSData dataWithContentsOfURL:imageurl]];
cell.imageViewSection = image;
cell.titleLabelText.text = textTitle;
return cell;
}
If someone can help me out it would be awesome :)
You should not rely on the cell always being returned as object at index 0 in the array. Do a simple loop to find the actual cell.
And add typecasts for the cell subclass you use
-(UITableViewCell*)tableView:(UITableView*)tableView
cellForRowAtIndexPath:(NSIndexPath*)indexPath
{
static NSString* cellID = #"cellID";
MyCell* cell = (id)[tableView dequeueReusableCellWithIdentifier:cellID];
if (cell == nil) {
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"TableViewCell"
owner:self
options:nil];
for (cell in nib) {
if ([cell isKindOfClass:[MyCell class]]) {
break;
}
}
}
// Safely do tuff to cell
return cell;
}
This snippet assumes that the cell is at least available, the behavior if no table view cell is returned is undefined.
You're assigning and casting TableViewCell to UITableViewCell variable and UITableViewCell does not have those outlets. Instead, you should do the following..
TableViewCell *cell = (TableViewCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"TableViewCell" owner:self options:nil];
cell = (TableViewCell *)[nib objectAtIndex:0];
}

Use multiple cell classes in tableViewController

Is there a way to use multiple uitableviewcell classes with nib files in the tableViewController?
There's this great tutorial video for how to create custom cell classes to be used in a tableViewController at the cellForRowAtIndexPath function that I'm pasting here in case anyone wants to see.
In this example though, they are only using one type of reusable cell class. This is from my own project but it's essentially what the tutorial presents. "videoCellEntry" is a custom cell that I have created with nib file videoEntryCell.xib, "videoEntry" is the class for each cell that I am configuring, and "videos" is an array of videoEntry.
I'm assuming to use multiple nib files, I can put some conditions to choose which nib file I want and then call a different loadNibNamed: portion like so:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"videoCellId";
videoEntryCell *cell =
(videoEntryCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
if(<condition 1>) {
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"videoEntryCell" owner:self options:nil];
}
if(<condition 2>) {
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"videoEntryCell2" owner:self options:nil];
}
cell = (videoEntryCell *)[nib objectAtIndex:0];
}
// Configure the cell.
videoEntry *vid = [videos objectAtIndex:indexPath.row];
[cell configureForVideoEntry:vid];
return cell;
}
But can the tableViewController handle multiple cell nib files? Or is there a better way? And wouldn't each cell require a different CellIdentifier depending on its nib file?
Yes, you can use multiple Nib-Files and multiple CellIdentifiers in the TableViewController. Just put your condition before the CellIdentifier. That's the way I've done it.
Some example inside the - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath method:
First define the variable cell:
UITableViewCell *cell;
Now the if-Block:
if(<condition 1>) {
static NSString *CellIdentifier = #"VideoCell1";
cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:#"videoEntryCell" owner:nil options:nil];
for (id currentObject in topLevelObjects){
if([currentObject isKindOfClass:[UITableViewCell class]]){
cell = (UITableViewCell *) currentObject;
break;
}
}
}
// customize your cell here
}
if(<condition 2>) {
static NSString *CellIdentifier = #"VideoCell2";
cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:#"videoEntryCell2" owner:nil options:nil];
for (id currentObject in topLevelObjects){
if([currentObject isKindOfClass:[UITableViewCell class]]){
cell = (UITableViewCell *) currentObject;
break;
}
}
}
// customize your cell here
}
and finally:
return cell;
You can repeat the if-Block as often as you want. It's only important that you return a cell, which is not nil.