I found some strange happens on my table. I want to create table with two or more section, and on the first section I want to use different custom cell with the others.
So I created this on my tableView:cellForRowAtIndexPath
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = #"cell";
if (indexPath.section == 0) {
// cell for section one
HeaderCell *headerCell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if(!headerCell) {
[tableView registerNib:[UINib nibWithNibName:#"HeaderCell" bundle:nil] forCellReuseIdentifier:cellIdentifier];
headerCell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
}
headerCell.labelName.text = #"First Section";
return headerCell;
}
else {
// Cell for another section
DetailCell *detailCell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (!detailSection) {
[tableView registerNib:[UINib nibWithNibName:#"DetailCell" bundle:nil] forCellReuseIdentifier:cellIdentifier];
detailCell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
}
detailCell.textLabel.text = #"Another Section Row";
return detailCell;
}
}
On the first section, I want to use headerCell for my row, then use detailCell on the others. This code works but on the section two's row looks like still using headerCell "under" detailCell. I added label into headerCell.xib, and it still shown on the detailCell. See this image.
I think all of this because I use one cell identifier for all of section. Anyone have solution? Thank you so much.
Each type of custom cell should have its own unique identifier. Your code is attempting to use the same cell identifier for all cells. That won't work.
Also, register the two cell types in viewDidLoad, not cellForRowAtIndexPath:.
Try this:
static NSString *cellIdentifier0 = #"cell0";
static NSString *cellIdentifier1 = #"cell1";
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.section == 0) {
// cell for section one
HeaderCell *headerCell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier0 forIndexPath:indexPath];
headerCell.labelName.text = #"First Section";
return headerCell;
} else {
// Cell for another section
DetailCell *detailCell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier1 forIndexPath:indexPath];
detailCell.textLabel.text = #"Another Section Row";
return detailCell;
}
}
- (void)viewDidLoad {
[super viewDidLoad];
// the rest of your code
[self.tableView registerNib:[UINib nibWithNibName:#"HeaderCell" bundle:nil] forCellReuseIdentifier:cellIdentifier0];
[self.tableView registerNib:[UINib nibWithNibName:#"DetailCell" bundle:nil] forCellReuseIdentifier:cellIdentifier1];
}
Related
I have create table cell with .xib file. and added in the UITableView using following code :
-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
DesplayCell *cell = [tableView dequeueReusableCellWithIdentifier:#"desplayCell"];
if (!cell) {
[tableView registerNib:[UINib nibWithNibName:#"DisplayCell" bundle:nil] forCellReuseIdentifier:#"desplayCell"];
}
//
return cell;
}
App crashes with error :
failed to obtain a cell from its dataSource
I forget to add dequeueReusableCellWithIdentifier in your code.
dequeueReusableCellWithIdentifier usage
You should use the same reuse identifier for all cells of the same form.
The reuse identifier is associated with those cells (rows) of a table view that have the same general configuration, minus cell content.
-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
DesplayCell *cell = [tableView dequeueReusableCellWithIdentifier:#"desplayCell"];
if (!cell) {
[tableView registerNib:[UINib nibWithNibName:#"DisplayCell" bundle:nil] forCellReuseIdentifier:#"desplayCell"];
cell = [tableView dequeueReusableCellWithIdentifier:#"desplayCell"];
}
//
return cell;
}
You can use like this
In viewDidLoad write below code
[tableView registerNib:[UINib nibWithNibName:#"DisplayCell" bundle:nil] forCellReuseIdentifier:#"desplayCell"];
In cellForRowAtIndexPath you can write below
-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
DesplayCell *cell = [tableView dequeueReusableCellWithIdentifier:#"desplayCell"];
if (cell == nil) { // if cell is nil then you can alloc it
cell=[[DesplayCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"desplayCell"];
cell = [tableView dequeueReusableCellWithIdentifier:#"desplayCell"];
}
return cell;
}
The answer is like Siddhesh Mhatre post But you should make a category of UITableView, it's useful for a large project.
UITableView+Category.h
- (id)dequeueReusableOrRegisterCellWithIdentifier:(NSString *)identifier;
- (id)dequeueReusableOrRegisterCellWithClass:(Class)aClass;
UITableView+Category.m
- (UITableViewCell *)dequeueReusableOrRegisterCellWithIdentifier:(NSString *)identifier{
UITableViewCell *cell = [self dequeueReusableCellWithIdentifier:identifier];
if (!cell) {
[self registerNib:[UINib nibWithNibName:identifier bundle:nil] forCellReuseIdentifier:identifier];
cell = [self dequeueReusableCellWithIdentifier:identifier];
}
return cell;
}
- (UITableViewCell *)dequeueReusableOrRegisterCellWithClass:(Class)aClass{
UITableViewCell *cell = [self dequeueReusableCellWithIdentifier:NSStringFromClass(aClass)];
if (!cell) {
[self registerClass:aClass forCellReuseIdentifier:NSStringFromClass(aClass)];
cell = [self dequeueReusableCellWithIdentifier:NSStringFromClass(aClass)];
}
return cell;
}
I have two UITableView and I want to use the same custom cell for both UITableView.
The problem is only one of them works fine. Only the first table display rows.
When I debug I see the cell.lb_subject is nil for the second table.
The MyCustomCell was defined as prototype cell(Is NOT a xib) only on the first table, because I don't see the point to define the same row twice.
- (UITableViewCell *)tableView:(UITableView *)mytableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *simpleTableIdentifier = #"MyCustomCell";
MyCustomCell *cell = [mytableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil) {
cell = [[MyCustomCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier];
}
MyRowData* data = [tableData objectAtIndex:indexPath.row];
cell.lb_subject.text = data.subject;
I have two UIViewController
One table per each UIViewController
I have not Xib, I have a storyboard.
I've uploaded to my repo a demo
Follow this step.
Your ViewController
ViewController.h
NSMutableArray *tableData;
ViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
tableData = [[NSMutableArray alloc]initWithObjects:#"test1",#"test2",#"test3",nil];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [tableData count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
//Here MyCustomCell is identifier for both tableview cell.
static NSString *simpleTableIdentifier = #"MyCustomCell";
//tblCell is your custom tableview cell.
tblCell *cell = [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil) {
cell = [[tblCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier];
}
cell.lb_subject.text = [tableData objectAtIndex:indexPath.row];
return cell;
}
Your Custom cell
tblCell.h
//Here lb_subject is common Outlet for both label of both cell.
#property (strong, nonatomic) IBOutlet UILabel *lb_subject;
Give Tag to your both tables and then use dequeueReusableCellWithIdentifier for both tables separately.
if (tableView.tag==1) {
static NSString *simpleTableIdentifier = #"MyCustomCell";
MyCustomCell *cell = [mytableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil) {
cell = [[MyCustomCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier];
}
MyRowData* data = [tableData objectAtIndex:indexPath.row];
cell.lb_subject.text = data.subject;
return cell;
}
else {
static NSString *simpleTableIdentifier = #"MyCustomCell";
MyCustomCell *cell = [mytableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil) {
cell = [[MyCustomCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier];
}
MyRowData* data = [tableData objectAtIndex:indexPath.row];
cell.lb_subject.text = data.subject;
return cell;
}
I would like to register the cell with the tableView in the class of customCell. something like this
class func cellForTableView(tableView: UITableView, atIndexPath indexPath: NSIndexPath) -> YourCustomTableViewCell {
let kYourCustomTableViewCellIdentifier = "kYourCustomTableViewCellIdentifier"
tableView.registerNib(UINib(nibName: "YourCustomTableViewCell", bundle: NSBundle.mainBundle()), forCellReuseIdentifier: kYourCustomTableViewCellIdentifier)
let cell = tableView.dequeueReusableCellWithIdentifier(kYourCustomTableViewCellIdentifier, forIndexPath: indexPath) as! YourCustomTableViewCell
return cell
}
You can see a more detailed answer Here.
I am guessing that you are having two prototype cell for each of your table.
Let's say for, table A - "CustomCellA" & for table B - "CustomCellB"
both customCell's parent class should be same.
Now in cellForRowAtIndexPath write below code,
MyCustomCell *cell;
if (tableView == tableViewA)
cell = [mytableView dequeueReusableCellWithIdentifier:#"CustomCellA"];
else
cell = [mytableView dequeueReusableCellWithIdentifier:#"CustomCellB"];
Your cell's Outlet and attributes should be find for both tableview.
Do let me know the results.
Thanks, Hope this helps.
You've not added cell in other table
if you do not want to create another prototype cell for viewController 2 then you need to use XIB
Register your XIB :
Register your customcell in ViewDidload instead of cellForRow
[self.tableView registerNib:[UINib nibWithNibName:#"CustomCell" bundle:[NSBundle mainBundle]] forCellReuseIdentifier:#"CustomCell"];
and,
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
CustomCell *cell = [tableView dequeueReusableCellWithIdentifier:#"CustomCell"];
if (cell == nil) {
NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:#"CustomCell" owner:self options:nil];
cell = (CustomCell *)[topLevelObjects objectAtIndex:0];
}
cell.cellLabel.text = _arrData[indexPath.row];
return cell;
}
If you still face same problem then let me know
My table simply has row with a UIImageView. When I assign the image directly like the below mentioned way
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *identifier = #"cellidentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier forIndexPath:indexPath];
// Configure the cell...
cell.imageView.image = [self.backgroundImages objectAtIndex:indexPath.row];
return cell;
}
It returns error:
unable to dequeue a cell with identifier cellidentifier - must
register a nib or a class for the identifier or connect a prototype
cell in a storyboard'.
So I wonder is there a way to ignore to register a nib or a class for UITableViewCell in order to shorten the code in this case?
If you are using custom class for your cell then you should register the class (in viewDidLoad),use registerNib:forCellWithReuseIdentifier: if the cell is made in a xib file.
[self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:#"Cell"];
else write cellForRowAtIndexPath tableView delegate as follows:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
//Configure cell
return cell;
}
You just need to add one line in your viewDidLoad to resolve the error
- (void)viewDidLoad
{
[super viewDidLoad];
[self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:#"cellidentifier"];
}
Put your cell identifier in storyboard as below screenshot.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Songcell"; // copy this identifier and paste it into your storyboard tableviewcell indetifier
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
UIImageView *IMAGEVIEWNAME = (UIImageView*)[cell viewWithTag:YOUR_TAG]; // give tag to your imageview from storyboard and access it here
IMAGEVIEWNAME.image = [UIImage imageNamed:#"YOURIMAGENAME"];
return cell;
}
Give same name in your storyboard tableviewcell identifier
cellidentifier with this name . i just give my cell identifier songcell.
- (void)viewDidLoad {
[super viewDidLoad];
[self.tableView registerNib:[UINib nibWithNibName:#"FriendTableViewCell" bundle:nil] forCellReuseIdentifier:#"FIDCELL"];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
FriendTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"FIDCELL"];
return cell;
}
This code block work but when i add new cell in FriendTableViewCell.xib not work actually i can not call new cell. How can i call this cell or this is possible ? If this question is not clear i can add image...
**
i try to call different cell from same .xib
**
Error:
I found solution i generate new .xib and call when page load both of them
[self.tableView registerNib:[UINib nibWithNibName:#"FriendTableViewCell" bundle:nil] forCellReuseIdentifier:#"FIDCELL"];
[self.tableView registerNib:[UINib nibWithNibName:#"Cell2" bundle:nil] forCellReuseIdentifier:#"FIDCELL2"];
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *cellID = #"";
if (indexPath.row % 2 == 0) {
cellID = #"FIDCELL";
} else {
cellID = #"FIDCELL2";
}
FriendTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID];
// Configure the cell...
cell.nameLabel.text = self.namesArray[indexPath.row];
cell.photoImageView.image = [UIImage imageNamed:self.photoNameArray[indexPath.row]];
return cell;
}
This code part totally work.
Okey so first of all , every cell should have its unique identifier so if the first cell have an identifier called "FIDCELL" the second one should have another one called "FIDCELL2" for example , and remove the following line from your viewDidLoad :
[self.tableView registerNib:[UINib nibWithNibName:#"FriendTableViewCell" bundle:nil] forCellReuseIdentifier:#"FIDCELL"];
and add this to cellForRowAtIndexPath
-(UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
CustomTableViewCell * cell ;
if(condtion1)
{
cell = [tableView dequeueReusableCellWithIdentifier:firstCellIdentfier];
}
else if(condtion2)
{
cell = [tableView dequeueReusableCellWithIdentifier:secondCellIdentfier];
}
if (cell == nil)
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:yourNibName owner:self options:nil];
if(condtion1)
{
//0 is the index of the first cell in the nib
cell = [nib objectAtIndex:0];
}
else if(condtion2)
{
//1 is the index of the second cell in the nib .
cell = [nib objectAtIndex:1] ;
}
}
//do other work
return cell ;
}
where condtion1 and and condtion2 is the conditions that will determine which cell will be chosen .
I am using a TableView xib and all the delegates and datasource seem to be running fine.
If I set self.textLabel.text, it displays the generic number of tableviews correctly, but I need to have my custom TableViewCell showing.
I created a HistoryCell.xib that has just a tableviewcell in it.
I created a UITableViewCell class "HistoryCell.h/HistoryCell.m" and it is set as the file owner of HistoryCell.xib.
I connected the UILabels to the HistoryCell.h
UILabel statusLabel
UILabel nameLabel
UILabel timeLabel
In my main ViewController class int he cellForRowAtIndexPath
I am putting in
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"historyCellType";
HistoryCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[HistoryCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
cell.nameLabel.text = #"Donald Duck";
return cell;
}
What am I doing wrong?
Thanks!
You should register the nib like this (probably in viewDidLoad):
[self.tableView registerNib:[UINib nibWithNibName:#"HistoryCell" bundle:nil ] forCellReuseIdentifier:#"historyCellType"];
Then in your cellForRowAtIndexPath method, use this new way where you don't need the if cell == nil clause:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
HistoryCell *cell = [tableView dequeueReusableCellWithIdentifier:#"historyCellType" forIndexPath:indexPath];
cell.nameLabel.text = #"Donald Duck";
return cell;
}
You need to deserialize the actual XIB data:
HistoryCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
NSArray *cellnib = [[NSBundle mainBundle] loadNibNamed:#"HistoryXIBName" owner:self options:nil];
cell = (HistoryCell *)[cellnib objectAtIndex:0];
}
Otherwise it's just using a "Default" cell.
EDIT: Also, if you are using storyboards, dynamic cell prototypes remove the need to create cells from NIB files (in case that's an option for you.)
EDIT The 2nd:
You can try this as well (this assumes you are using ARC):
HistoryCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
HistoryCell *aNewCell = [[HistoryCell alloc] initWithNibName:#"HistoryXIBName" bundle:nil];
cell = (HistoryCell *)*aNewCell.view;
}
There's another method using outlets to your cell in the containing view's XIB file that's a bit more involved that I used to use when iOS4 was current. If the edited version isn't' working for you, I'll dig out an old project and remember how I did it.
When you use tableViewCell with xib, while instantiation load from xib.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"historyCellType";
HistoryCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[NSBundle mainBundle]loadNibNamed:#"HistoryCell"
owner:nil
options:nil]lastObject];
}
cell.nameLabel.text = #"Donald Duck";
return cell;
}
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *cellidentifier=#"cell1";
customcell *cell =
(customcell*)[tableView dequeueReusableCellWithIdentifier:cellidentifier];
if (cell==nil) {
[tableView registerNib:[UINib nibWithNibName:#"Customcell" bundle:nil]
forCellReuseIdentifier:cellidentifier];
cell =
(customcell*)[tableView dequeueReusableCellWithIdentifier:cellidentifier
forIndexPath:[NSIndexPath indexPathForItem:indexPath.row
inSection:indexPath.section]];
}
return cell;
}