How should I implement a custom table view cell? - ios

I am trying to change a cell in a tableview from generic to custom and have created a new tableview cell class. However, I cannot get the cell to recognize the new custom cell. Instead, it is still displaying the generic cell although I've changed the setting in storyboard to custom in the identify inspector and also changed the class for the tableview cell to the new custom one. I have also wired the elements in the cell in storyboard to the new custom class.
My understanding is the tableview VC knows which class to use from the tableView cellForRowAtIndexPath method and I have changed that too with the code below. The project compiles but continues to show old generic cell. Can anyone see error or suggest what else to do?
#import "customCell.h"
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
customCell *cell = (customCell *)[self.tableView dequeueReusableCellWithIdentifier:#"Cell"];
Items *item = [self.fetchedResultsController objectAtIndexPath:indexPath];
return cell;
}
Thanks in advance for any suggestions.
Edit:
A custom cell is created in the storyboard on top of tableview by dragging uielements. Maybe this is an issue:
Style of cell is set to Custom:

You need to create new UITableViewCell and enable the "create XIB file...".
Create your custom cell in the XIB and make it's custom class as your class you just created.
Then in tableView cellForRowAtIndexPath register the Nib: (it's in swift but I bet you can figure out the objective c parallel...)
tableView.registerNib(UINib(nibName: "YourUITableViewCellClass", bundle: nil), forCellReuseIdentifier: "YourCustomIdentifierFromTheCustomClass")
Then access your cell:
var cell = tableView.dequeueReusableCellWithIdentifier("YourCustomIdentifierFromTheCustomClass")
and that's it.

you can create custom cell in your main story board by drag the cell view.
create custom class for that prototype.
mention the class name in identifier inspector.
import that class to your view controller .h file.
and made connection of your custom from main story board to custom class.h file.
it works!.

When you create a custom cell you have to do these things:
Setup the labels, images etc on storyboard cell.
Create a custom cell class (inheriting from
UITableViewCell)(CustomCell.h & .m), CustomCell.h having all of the
properties as iboutlet for labels, images etc. and synthesize them all
in implementation.
After creating this custom class go back to storyboard, select the
custom cell, change its class to the CustomCell and give it some
identifier like "MyCustomCell", then right click on the custom cell
and connect the IBOutlets with labels etc.
Now import CustomCell class in the class where you are implementing
the UITableView and use the properties you defined in CustomCell
class.
- (UITableViewCell *)tableView: (UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *) indexPath
{
static NSString *MyIdentifier = #"MyCustomCell";
CustomCell*cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:MyIdentifier] autorelease];
}
// Here we use the provided setImageWithURL: method to load the web image
// Ensure you use a placeholder image otherwise cells will be initialized with no image
[cell.imageView setImageWithURL:[NSURL URLWithString:#"http://example.com/image.jpg"]
placeholderImage:[UIImage imageNamed:#"placeholder"]];
cell.myCustomLabel.text = #"My Text";
return cell; }

Select the cell on your Storyboard, and enter the name of your class in this field.
When you dequeue it from the identifier, it'll be an instance of that class.

Please note that each regular tableViewCell has a builtin and hidden UIImageView.
In Objective-C, you simply do this within your cellForRowAtIndexPath,
cell.imageView.image = [UIImage imageNamed:#"My awesome image"];
In Swift, it's pretty close.
cell.imageView?.image = UIImage(named: "My awesome image")

Related

Declaring array error in swift2 [duplicate]

So I was making an rss reader for my school and finished the code. I ran the test and it gave me that error. Here is the code it's referring to:
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell =
[tableView dequeueReusableCellWithIdentifier:CellIdentifier
forIndexPath:indexPath];
if (cell == nil) {
cell =
[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle
reuseIdentifier:CellIdentifier];
}
here's the error in the output:
2012-10-04 20:13:05.356 Reader[4390:c07] * Assertion failure in
-[UITableView dequeueReusableCellWithIdentifier:forIndexPath:], /SourceCache/UIKit_Sim/UIKit-2372/UITableView.m:4460 2012-10-04
20:13:05.357 Reader[4390:c07] * Terminating app due to uncaught
exception 'NSInternalInconsistencyException', reason: 'unable to
dequeue a cell with identifier Cell - must register a nib or a class
for the identifier or connect a prototype cell in a storyboard'
* First throw call stack: (0x1c91012 0x10cee7e 0x1c90e78 0xb64f35 0xc7d14 0x39ff 0xd0f4b 0xd101f 0xb980b 0xca19b 0x6692d 0x10e26b0
0x228dfc0 0x228233c 0x228deaf 0x1058cd 0x4e1a6 0x4ccbf 0x4cbd9 0x4be34
0x4bc6e 0x4ca29 0x4f922 0xf9fec 0x46bc4 0x47311 0x2cf3 0x137b7 0x13da7
0x14fab 0x26315 0x2724b 0x18cf8 0x1becdf9 0x1becad0 0x1c06bf5
0x1c06962 0x1c37bb6 0x1c36f44 0x1c36e1b 0x147da 0x1665c 0x2a02 0x2935)
libc++abi.dylib: terminate called throwing an exception
and here's the code it shows in the error screen:
int main(int argc, char *argv[])
{
#autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}
please help!
You're using the dequeueReusableCellWithIdentifier:forIndexPath: method. The documentation for that method says this:
Important: You must register a class or nib file using the registerNib:forCellReuseIdentifier: or registerClass:forCellReuseIdentifier: method before calling this method.
You didn't register a nib or a class for the reuse identifier "Cell".
Looking at your code, you seem to expect the dequeue method to return nil if it doesn't have a cell to give you. You need to use the dequeueReusableCellWithIdentifier: for that behavior:
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
Notice that dequeueReusableCellWithIdentifier: and dequeueReusableCellWithIdentifier:forIndexPath: are different methods. See doc for the former and the latter.
If you want to understand why you'd want to ever use dequeueReusableCellWithIdentifier:forIndexPath:, check out this Q&A.
I think this error is about registering your nib or class for the identifier.
So that you may keep what you are doing in your tableView:cellForRowAtIndexPath function and just add code below into your viewDidLoad:
[self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:#"Cell"];
It's worked for me. Hope it may help.
Although this question is fairly old, there is another possibility:
If you are using Storyboards, you simply have to set the CellIdentifier in the Storyboard.
So if your CellIdentifier is "Cell", just set the "Identifier" property:
Make sure to clean your build after doing so. XCode sometimes has some issues with Storyboard updates
i had the same problem replacing with
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell==nil) {
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
solved
The problem is most likely because you config custom UITableViewCell in storyboard but you do not use storyboard to instantiate your UITableViewController which uses this UITableViewCell. For example, in MainStoryboard, you have a UITableViewController subclass called MyTableViewController and have a custom dynamic UITableViewCell called MyTableViewCell with identifier id "MyCell".
If you create your custom UITableViewController like this:
MyTableViewController *myTableViewController = [[MyTableViewController alloc] init];
It will not automatically register your custom tableviewcell for you. You have to manually register it.
But if you use storyboard to instantiate MyTableViewController, like this:
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle:nil];
MyTableViewController *myTableViewController = [storyboard instantiateViewControllerWithIdentifier:#"MyTableViewController"];
Nice thing happens! UITableViewController will automatically register your custom tableview cell that you define in storyboard for you.
In your delegate method "cellForRowAtIndexPath", you can create you table view cell like this :
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"MyCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
//Configure your cell here ...
return cell;
}
dequeueReusableCellWithIdentifier will automatically create new cell for you if there is not reusable cell available in the recycling queue.
Then you are done!
I'll just add that Xcode 4.5 includes the new dequeueReusableCellWithIdentifier:forIndexPath:
in its default template code - a potential gotcha for developers expecting the older dequeueReusableCellWithIdentifier: method.
Swift 2.0 solution:
You need to go into your Attribute Inspector and add a name for your cells Identifier:
Then you need to make your identifier match with your dequeue like this:
let cell2 = tableView.dequeueReusableCellWithIdentifier("ButtonCell", forIndexPath: indexPath) as! ButtonCell
Alternatively
If you're working with a nib you may need to register your class in your cellForRowAtIndexPath:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "SwitchCell")
// included for context
let cell = tableView.dequeueReusableCellWithIdentifier("SwitchCell", forIndexPath:indexPath) as! SwitchCell
//... continue
}
Apples's UITableView Class Reference says:
Prior to dequeueing any cells, call this method or the
registerNib:forCellReuseIdentifier: method to tell the table view how
to create new cells. If a cell of the specified type is not currently
in a reuse queue, the table view uses the provided information to
create a new cell object automatically.
If you previously registered a class or nib file with the same reuse
identifier, the class you specify in the cellClass parameter replaces
the old entry. You may specify nil for cellClass if you want to
unregister the class from the specified reuse identifier.
Here's the code from Apples Swift 2.0 framework:
// Beginning in iOS 6, clients can register a nib or class for each cell.
// If all reuse identifiers are registered, use the newer -dequeueReusableCellWithIdentifier:forIndexPath: to guarantee that a cell instance is returned.
// Instances returned from the new dequeue method will also be properly sized when they are returned.
#available(iOS 5.0, *)
func registerNib(nib: UINib?, forCellReuseIdentifier identifier: String)
#available(iOS 6.0, *)
func registerClass(cellClass: AnyClass?, forCellReuseIdentifier identifier: String)
In your storyboard you should set the 'Identifier' of your prototype cell to be the same as your CellReuseIdentifier "Cell". Then you won't get that message or need to call that registerClass: function.
If you are going with Custom Static Cells just comment this method:
//- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
// static NSString *CellIdentifier = #"notificationCell";
// UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
// return cell;
//}
and give the cells an identifier at "Attributes Inspector" in storyboard.
I give you the answer in both Objective C and Swift.Before that I want to say
If we use the dequeueReusableCellWithIdentifier:forIndexPath:,we must register a class or nib file using the registerNib:forCellReuseIdentifier: or registerClass:forCellReuseIdentifier: method before calling this method as
Apple Documnetation Says
So we add registerNib:forCellReuseIdentifier: or registerClass:forCellReuseIdentifier:
Once we registered a class for the specified identifier and a new cell must be created, this method initializes the cell by calling its initWithStyle:reuseIdentifier: method. For nib-based cells, this method loads the cell object from the provided nib file. If an existing cell was available for reuse, this method calls the cell’s prepareForReuse method instead.
in viewDidLoad method we should register the cell
Objective C
OPTION 1:
[self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:#"cell"];
OPTION 2:
[self.tableView registerNib:[UINib nibWithNibName:#"CustomCell" bundle:nil] forCellReuseIdentifier:#"cell"];
in above code nibWithNibName:#"CustomCell" give your nib name instead of my nib name CustomCell
SWIFT
OPTION 1:
tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "cell")
OPTION 2:
tableView.registerNib(UINib(nibName: "NameInput", bundle: nil), forCellReuseIdentifier: "Cell")
in above code nibName:"NameInput" give your nib name
Working with Swift 3.0:
override func viewDidLoad() {
super.viewDidLoad()
self.myList.register(UINib(nibName: "MyTableViewCell", bundle: nil), forCellReuseIdentifier: "Cell")
}
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = myList.dequeueReusableCell(withIdentifier: "Cell", for: indexPath as IndexPath) as! MyTableViewCell
return cell
}
I spent hours last night working out why my programmatically generated table crashed on [myTable setDataSource:self]; It was OK commenting out and popping up an empty table, but crashed every time I tried to reach the datasource;
I had the delegation set up in the h file: #interface myViewController : UIViewController
I had the data source code in my implementation and still BOOM!, crash every time! THANK YOU to "xxd" (nr 9): adding that line of code solved it for me! In fact I am launching a table from a IBAction button, so here is my full code:
- (IBAction)tapButton:(id)sender {
UIViewController* popoverContent = [[UIViewController alloc]init];
UIView* popoverView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 200, 300)];
popoverView.backgroundColor = [UIColor greenColor];
popoverContent.view = popoverView;
//Add the table
UITableView *table = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, 200, 300) style:UITableViewStylePlain];
// NEXT THE LINE THAT SAVED MY SANITY Without it the program built OK, but crashed when tapping the button!
[table registerClass:[UITableViewCell class] forCellReuseIdentifier:#"Cell"];
table.delegate=self;
[table setDataSource:self];
[popoverView addSubview:table];
popoverContent.contentSizeForViewInPopover =
CGSizeMake(200, 300);
//create a popover controller
popoverController3 = [[UIPopoverController alloc]
initWithContentViewController:popoverContent];
CGRect popRect = CGRectMake(self.tapButton.frame.origin.x,
self.tapButton.frame.origin.y,
self.tapButton.frame.size.width,
self.tapButton.frame.size.height);
[popoverController3 presentPopoverFromRect:popRect inView:self.view permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
}
#Table view data source in same m file
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
NSLog(#"Sections in table");
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
NSLog(#"Rows in table");
// Return the number of rows in the section.
return myArray.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
NSString *myValue;
//This is just some test array I created:
myValue=[myArray objectAtIndex:indexPath.row];
cell.textLabel.text=myValue;
UIFont *myFont = [ UIFont fontWithName: #"Arial" size: 12.0 ];
cell.textLabel.font = myFont;
return cell;
}
By the way: the button must be linked up with as an IBAction and as a IBOutlet if you want to anchor the popover to it.
UIPopoverController *popoverController3 is declared in the H file directly after #interface between {}
FWIW, I got this same error when I forgot to set the cell identifier in the storyboard. If this is your issue then in the storyboard click the table view cell and set the cell identifier in the attributes editor. Make sure the cell identifier you set here is the same as
static NSString *CellIdentifier = #"YourCellIdenifier";
I had the same issue, was having the same error and for me it worked like this:
[self.tableView registerNib:[UINib nibWithNibName:CELL_NIB_HERE bundle: nil] forCellReuseIdentifier:CELL_IDENTIFIER_HERE];
Maybe it will be usefull for someone else.
I setup everything correctly in the Storyboard and did a clean build but kept getting the error " must register a nib or a class for the identifier or connect a prototype cell in a storyboard"
[self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:#"Cell"];
Corrected the error but i'm still at a loss. I'm not using a 'custom cell', just a view with a tableview embeded. I have declared the viewcontroller as delegate and datasource and made sure the cell identifier matches in file. whats going on here?
This might seem stupid to some people but it got me. I was getting this error and the problem for me was that I was trying to use static cells but then dynamically add more stuff. If you are calling this method your cells need to be dynamic prototypes. Select the cell in storyboard and under the Attributes inspector, the very first thing says 'Content' and you should select dynamic prototypes not static.
Just a supplement of the answers:
There may be a time you set all things right, but you may accidentally add some other UIs in you .xib, like a UIButton:
Just delete the extra UI, it works.
Make sure that the CellIdentifier == identifier of the cell in a storyboard, both names are same. Hope this works for u
In my case, the crash happened when I calleddeselectRowAtIndexPath:
The line was [tableView deselectRowAtIndexPath:indexPath animated:YES];
Changing it to [self.tableView deselectRowAtIndexPath:indexPath animated:YES]; FIXED MY PROBLEM!
Hope this helps anyone
In Swift this problem can be solved by adding the following code in your
viewDidLoad
method.
tableView.registerClass(UITableViewCell.classForKeyedArchiver(), forCellReuseIdentifier: "your_reuse_identifier")
you have to be aware that when using interface builder and creating a Xib (nib) containing one cell that there is also a placeholder created that points to the class that will be used. Meaning, when you place two UITableViewCell in one Xib file you possibly run into the exact same trouble causing an *** Assertion failure .... The placeholder mechanism doesn't work adn will be confused then. Instead placing different placeholders in one Xib read on..
The most easy solution (even if that seems a bit to simple) is to place one Cell at a time in one Xib. IB will create a placeholder for you and all works as expected then. But this then leads directly to one extra line of code, because then you need to load the correct nib/xib asking for the reuseIdentified Cell where it resides in.
So the following example code focuses the use of multiple Cell Indentifiers in one tableview where an Assertion Failure is very common.
// possibly above class implementation
static NSString *firstCellIdentifier = #"firstCellIdentifier";
static NSString *secondCellIdentifier = #"secondCellIdentifier";
// possibly in -(instancetype)init
UINib *firstNib = [UINib nibWithNibName:#"FirstCell" bundle:nil];
[self.tableView registerNib:firstNib forCellReuseIdentifier:firstCellIdentifier];
UINib *secondNib = [UINib nibWithNibName:#"SecondCell" bundle:nil];
[self.tableView registerNib:secondNib forCellReuseIdentifier:secondCellIdentifier];
Another trouble with the use of two CellIdentifier's in one UITableView is that row height and/or section height have to be taken care of. Two cells can have different heights of course.
When registering classes for reuse the code should look different.
The "simple solution" looks also much different when your cells reside inside a Storyboard instead of Xib's. Watch out for the placeholders.
Keep also in mind that interface builder files have version wise variations and need to be set to a version that your targeted OS version supports. Even if you may be lucky that the particular feature you placed in your Xib is not changed since the last IB version and does not throw errors yet. So a Xib made with IB set to be compatible to iOS 13+ but used in a target that is compiled on an earlier version iOS 12.4 will cause also trouble and can end up with Assertion failure.
Ran into this error bc cell re-use identifier was wrong-- a rookie mistake but it happens:
1. Makes SURE cell re-use idenifier has no misspellings or missing letters.
2. Along same line, don't forget capitalization counts.
3. Zeroes are not "O"s (Ohs)

Custom prototype cell xcode 6

Good morning,
I would like to create a custom design for my prototype cell and I don't have any idea on how to do that. I have tried to follow some guides or tutorials but I always get some error and there is something that I'm not doing right.
At the moment I'm using the default prototye cell to display the following:
http://i.stack.imgur.com/TnYGZ.png
Now I would like to insert a UIImageView, and also 2 UILabels (something like Facebook) with the author and the image displayed in the prototype cell.
How can I do that? Can you show me some example or a good tutorial to follow?
Thanks in advance.
A brief list of things to do in order to achieve your goal is:
1) Create a Cocoa Touch Class File subclass of UITableViewCell
2) Click on storyboard, and change the class of your cell to this one you created
3) Create your IBOutlets for the views you added to your cell (UILabel, UIImageView, etc)
4) Then under cellForRowAtIndexPath, dequeue your customCell and pass data to your views
For example:
CustomCell *cell = [tableView dequeueReusableCellWithIdentifier:#"yourCellIdentifier" forIndexPath:indexPath];
cell.yourImageView.image = [UIImage imageNamed:#"yourImage"];
cell.yourLabel.text = #"Your text";
These are the basic steps to configure your cell, but you can follow this tutorial here since you are a new iOS Developer, and a Video Tutorial comes more handy for you.
Creating a Custom UITableViewCell
Check this tutorial for how to make custom cell with different ways, and this that discuss it in details starting from how to use storyboards.
eridb explained you with IBOutlet. If you want to do that programmatically;
1-) Create new UITableViewCell class. (e.g NewTableViewCell)
2-) Create your properties in NewTableViewCell.h
3-) Create and customize your properties in NewTableViewCell.m like that;
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self)
{
// create label, uiimageview, etc. here
}
return self;
}
4-) Ok, your custom UITableViewCell class is ready. Now, call it whereever you want to use (e.g NewTableViewController);
#import "NewTableViewCell.h"
5-) Configure your cell in cellForRowAtIndexPath like that;
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *reuseIdentifier = #"myTableViewID";
NewTableViewCell *cell = (NewTableViewCell *)[tableView dequeueReusableCellWithIdentifier:reuseIdentifier];
if(cell == nil)
{
cell = [[NewTableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:reuseIdentifier];
}
cell.yourCustomLabel.text = #"Label-1 text";
cell.yourCustomImageView.image = [UIImage imageNamed:#"test"];
return cell;
}

Why am I getting three "Illegal Configuration" errors within my project?

I have a project where I have three labels in a custom cell prototype class (subclass of UITableViewCell) that are linked to three label outlets in the custom cell's .h file.
Then in my main viewcontroller class (which houses the prototype cells and is a subclass of UITableViewController) my delegate method that interacts with these labels looks like this:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"ArticleCell";
ArticleCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
int row = indexPath.row;
cell.articleTitle.text = self.articleTitles[row];
cell.articleURL.text = self.articleURLs[row];
cell.articlePreview.text = self.articleURLs[row];
return cell;
}
Yet I get these three errors:
Connection "articleURL" cannot have a prototype object as its destination.
Connection "articlePreview" cannot have a prototype object as its destination.
Connection "articleTitle" cannot have a prototype object as its destination.
What exactly am I doing wrong? I'm so confused.
You might be connecting the Label outlets wrong in your project. I assume that labels articleURL, articlePreview and articleTitle are defined in the UITableViewCell. They should be connected for outlets in the corresponding customTableViewCell class not in the UIViewController. As you are referencing self.articleTitles in cellForRowAtIndexPath, it suggests that you are connecting them as outlets of current class not the customTableViewCell class. It is good idea to define your customTableCell as a property to your current class which is having UITableView's Delegate implemented.
Have a look at TableView Programming for details.

Assertion failure in dequeueReusableCellWithIdentifier:forIndexPath:

So I was making an rss reader for my school and finished the code. I ran the test and it gave me that error. Here is the code it's referring to:
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell =
[tableView dequeueReusableCellWithIdentifier:CellIdentifier
forIndexPath:indexPath];
if (cell == nil) {
cell =
[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle
reuseIdentifier:CellIdentifier];
}
here's the error in the output:
2012-10-04 20:13:05.356 Reader[4390:c07] * Assertion failure in
-[UITableView dequeueReusableCellWithIdentifier:forIndexPath:], /SourceCache/UIKit_Sim/UIKit-2372/UITableView.m:4460 2012-10-04
20:13:05.357 Reader[4390:c07] * Terminating app due to uncaught
exception 'NSInternalInconsistencyException', reason: 'unable to
dequeue a cell with identifier Cell - must register a nib or a class
for the identifier or connect a prototype cell in a storyboard'
* First throw call stack: (0x1c91012 0x10cee7e 0x1c90e78 0xb64f35 0xc7d14 0x39ff 0xd0f4b 0xd101f 0xb980b 0xca19b 0x6692d 0x10e26b0
0x228dfc0 0x228233c 0x228deaf 0x1058cd 0x4e1a6 0x4ccbf 0x4cbd9 0x4be34
0x4bc6e 0x4ca29 0x4f922 0xf9fec 0x46bc4 0x47311 0x2cf3 0x137b7 0x13da7
0x14fab 0x26315 0x2724b 0x18cf8 0x1becdf9 0x1becad0 0x1c06bf5
0x1c06962 0x1c37bb6 0x1c36f44 0x1c36e1b 0x147da 0x1665c 0x2a02 0x2935)
libc++abi.dylib: terminate called throwing an exception
and here's the code it shows in the error screen:
int main(int argc, char *argv[])
{
#autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}
please help!
You're using the dequeueReusableCellWithIdentifier:forIndexPath: method. The documentation for that method says this:
Important: You must register a class or nib file using the registerNib:forCellReuseIdentifier: or registerClass:forCellReuseIdentifier: method before calling this method.
You didn't register a nib or a class for the reuse identifier "Cell".
Looking at your code, you seem to expect the dequeue method to return nil if it doesn't have a cell to give you. You need to use the dequeueReusableCellWithIdentifier: for that behavior:
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
Notice that dequeueReusableCellWithIdentifier: and dequeueReusableCellWithIdentifier:forIndexPath: are different methods. See doc for the former and the latter.
If you want to understand why you'd want to ever use dequeueReusableCellWithIdentifier:forIndexPath:, check out this Q&A.
I think this error is about registering your nib or class for the identifier.
So that you may keep what you are doing in your tableView:cellForRowAtIndexPath function and just add code below into your viewDidLoad:
[self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:#"Cell"];
It's worked for me. Hope it may help.
Although this question is fairly old, there is another possibility:
If you are using Storyboards, you simply have to set the CellIdentifier in the Storyboard.
So if your CellIdentifier is "Cell", just set the "Identifier" property:
Make sure to clean your build after doing so. XCode sometimes has some issues with Storyboard updates
i had the same problem replacing with
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell==nil) {
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
solved
The problem is most likely because you config custom UITableViewCell in storyboard but you do not use storyboard to instantiate your UITableViewController which uses this UITableViewCell. For example, in MainStoryboard, you have a UITableViewController subclass called MyTableViewController and have a custom dynamic UITableViewCell called MyTableViewCell with identifier id "MyCell".
If you create your custom UITableViewController like this:
MyTableViewController *myTableViewController = [[MyTableViewController alloc] init];
It will not automatically register your custom tableviewcell for you. You have to manually register it.
But if you use storyboard to instantiate MyTableViewController, like this:
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle:nil];
MyTableViewController *myTableViewController = [storyboard instantiateViewControllerWithIdentifier:#"MyTableViewController"];
Nice thing happens! UITableViewController will automatically register your custom tableview cell that you define in storyboard for you.
In your delegate method "cellForRowAtIndexPath", you can create you table view cell like this :
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"MyCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
//Configure your cell here ...
return cell;
}
dequeueReusableCellWithIdentifier will automatically create new cell for you if there is not reusable cell available in the recycling queue.
Then you are done!
I'll just add that Xcode 4.5 includes the new dequeueReusableCellWithIdentifier:forIndexPath:
in its default template code - a potential gotcha for developers expecting the older dequeueReusableCellWithIdentifier: method.
Swift 2.0 solution:
You need to go into your Attribute Inspector and add a name for your cells Identifier:
Then you need to make your identifier match with your dequeue like this:
let cell2 = tableView.dequeueReusableCellWithIdentifier("ButtonCell", forIndexPath: indexPath) as! ButtonCell
Alternatively
If you're working with a nib you may need to register your class in your cellForRowAtIndexPath:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "SwitchCell")
// included for context
let cell = tableView.dequeueReusableCellWithIdentifier("SwitchCell", forIndexPath:indexPath) as! SwitchCell
//... continue
}
Apples's UITableView Class Reference says:
Prior to dequeueing any cells, call this method or the
registerNib:forCellReuseIdentifier: method to tell the table view how
to create new cells. If a cell of the specified type is not currently
in a reuse queue, the table view uses the provided information to
create a new cell object automatically.
If you previously registered a class or nib file with the same reuse
identifier, the class you specify in the cellClass parameter replaces
the old entry. You may specify nil for cellClass if you want to
unregister the class from the specified reuse identifier.
Here's the code from Apples Swift 2.0 framework:
// Beginning in iOS 6, clients can register a nib or class for each cell.
// If all reuse identifiers are registered, use the newer -dequeueReusableCellWithIdentifier:forIndexPath: to guarantee that a cell instance is returned.
// Instances returned from the new dequeue method will also be properly sized when they are returned.
#available(iOS 5.0, *)
func registerNib(nib: UINib?, forCellReuseIdentifier identifier: String)
#available(iOS 6.0, *)
func registerClass(cellClass: AnyClass?, forCellReuseIdentifier identifier: String)
In your storyboard you should set the 'Identifier' of your prototype cell to be the same as your CellReuseIdentifier "Cell". Then you won't get that message or need to call that registerClass: function.
If you are going with Custom Static Cells just comment this method:
//- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
// static NSString *CellIdentifier = #"notificationCell";
// UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
// return cell;
//}
and give the cells an identifier at "Attributes Inspector" in storyboard.
I give you the answer in both Objective C and Swift.Before that I want to say
If we use the dequeueReusableCellWithIdentifier:forIndexPath:,we must register a class or nib file using the registerNib:forCellReuseIdentifier: or registerClass:forCellReuseIdentifier: method before calling this method as
Apple Documnetation Says
So we add registerNib:forCellReuseIdentifier: or registerClass:forCellReuseIdentifier:
Once we registered a class for the specified identifier and a new cell must be created, this method initializes the cell by calling its initWithStyle:reuseIdentifier: method. For nib-based cells, this method loads the cell object from the provided nib file. If an existing cell was available for reuse, this method calls the cell’s prepareForReuse method instead.
in viewDidLoad method we should register the cell
Objective C
OPTION 1:
[self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:#"cell"];
OPTION 2:
[self.tableView registerNib:[UINib nibWithNibName:#"CustomCell" bundle:nil] forCellReuseIdentifier:#"cell"];
in above code nibWithNibName:#"CustomCell" give your nib name instead of my nib name CustomCell
SWIFT
OPTION 1:
tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "cell")
OPTION 2:
tableView.registerNib(UINib(nibName: "NameInput", bundle: nil), forCellReuseIdentifier: "Cell")
in above code nibName:"NameInput" give your nib name
Working with Swift 3.0:
override func viewDidLoad() {
super.viewDidLoad()
self.myList.register(UINib(nibName: "MyTableViewCell", bundle: nil), forCellReuseIdentifier: "Cell")
}
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = myList.dequeueReusableCell(withIdentifier: "Cell", for: indexPath as IndexPath) as! MyTableViewCell
return cell
}
I spent hours last night working out why my programmatically generated table crashed on [myTable setDataSource:self]; It was OK commenting out and popping up an empty table, but crashed every time I tried to reach the datasource;
I had the delegation set up in the h file: #interface myViewController : UIViewController
I had the data source code in my implementation and still BOOM!, crash every time! THANK YOU to "xxd" (nr 9): adding that line of code solved it for me! In fact I am launching a table from a IBAction button, so here is my full code:
- (IBAction)tapButton:(id)sender {
UIViewController* popoverContent = [[UIViewController alloc]init];
UIView* popoverView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 200, 300)];
popoverView.backgroundColor = [UIColor greenColor];
popoverContent.view = popoverView;
//Add the table
UITableView *table = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, 200, 300) style:UITableViewStylePlain];
// NEXT THE LINE THAT SAVED MY SANITY Without it the program built OK, but crashed when tapping the button!
[table registerClass:[UITableViewCell class] forCellReuseIdentifier:#"Cell"];
table.delegate=self;
[table setDataSource:self];
[popoverView addSubview:table];
popoverContent.contentSizeForViewInPopover =
CGSizeMake(200, 300);
//create a popover controller
popoverController3 = [[UIPopoverController alloc]
initWithContentViewController:popoverContent];
CGRect popRect = CGRectMake(self.tapButton.frame.origin.x,
self.tapButton.frame.origin.y,
self.tapButton.frame.size.width,
self.tapButton.frame.size.height);
[popoverController3 presentPopoverFromRect:popRect inView:self.view permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
}
#Table view data source in same m file
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
NSLog(#"Sections in table");
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
NSLog(#"Rows in table");
// Return the number of rows in the section.
return myArray.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
NSString *myValue;
//This is just some test array I created:
myValue=[myArray objectAtIndex:indexPath.row];
cell.textLabel.text=myValue;
UIFont *myFont = [ UIFont fontWithName: #"Arial" size: 12.0 ];
cell.textLabel.font = myFont;
return cell;
}
By the way: the button must be linked up with as an IBAction and as a IBOutlet if you want to anchor the popover to it.
UIPopoverController *popoverController3 is declared in the H file directly after #interface between {}
FWIW, I got this same error when I forgot to set the cell identifier in the storyboard. If this is your issue then in the storyboard click the table view cell and set the cell identifier in the attributes editor. Make sure the cell identifier you set here is the same as
static NSString *CellIdentifier = #"YourCellIdenifier";
I had the same issue, was having the same error and for me it worked like this:
[self.tableView registerNib:[UINib nibWithNibName:CELL_NIB_HERE bundle: nil] forCellReuseIdentifier:CELL_IDENTIFIER_HERE];
Maybe it will be usefull for someone else.
I setup everything correctly in the Storyboard and did a clean build but kept getting the error " must register a nib or a class for the identifier or connect a prototype cell in a storyboard"
[self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:#"Cell"];
Corrected the error but i'm still at a loss. I'm not using a 'custom cell', just a view with a tableview embeded. I have declared the viewcontroller as delegate and datasource and made sure the cell identifier matches in file. whats going on here?
This might seem stupid to some people but it got me. I was getting this error and the problem for me was that I was trying to use static cells but then dynamically add more stuff. If you are calling this method your cells need to be dynamic prototypes. Select the cell in storyboard and under the Attributes inspector, the very first thing says 'Content' and you should select dynamic prototypes not static.
Just a supplement of the answers:
There may be a time you set all things right, but you may accidentally add some other UIs in you .xib, like a UIButton:
Just delete the extra UI, it works.
Make sure that the CellIdentifier == identifier of the cell in a storyboard, both names are same. Hope this works for u
In my case, the crash happened when I calleddeselectRowAtIndexPath:
The line was [tableView deselectRowAtIndexPath:indexPath animated:YES];
Changing it to [self.tableView deselectRowAtIndexPath:indexPath animated:YES]; FIXED MY PROBLEM!
Hope this helps anyone
In Swift this problem can be solved by adding the following code in your
viewDidLoad
method.
tableView.registerClass(UITableViewCell.classForKeyedArchiver(), forCellReuseIdentifier: "your_reuse_identifier")
you have to be aware that when using interface builder and creating a Xib (nib) containing one cell that there is also a placeholder created that points to the class that will be used. Meaning, when you place two UITableViewCell in one Xib file you possibly run into the exact same trouble causing an *** Assertion failure .... The placeholder mechanism doesn't work adn will be confused then. Instead placing different placeholders in one Xib read on..
The most easy solution (even if that seems a bit to simple) is to place one Cell at a time in one Xib. IB will create a placeholder for you and all works as expected then. But this then leads directly to one extra line of code, because then you need to load the correct nib/xib asking for the reuseIdentified Cell where it resides in.
So the following example code focuses the use of multiple Cell Indentifiers in one tableview where an Assertion Failure is very common.
// possibly above class implementation
static NSString *firstCellIdentifier = #"firstCellIdentifier";
static NSString *secondCellIdentifier = #"secondCellIdentifier";
// possibly in -(instancetype)init
UINib *firstNib = [UINib nibWithNibName:#"FirstCell" bundle:nil];
[self.tableView registerNib:firstNib forCellReuseIdentifier:firstCellIdentifier];
UINib *secondNib = [UINib nibWithNibName:#"SecondCell" bundle:nil];
[self.tableView registerNib:secondNib forCellReuseIdentifier:secondCellIdentifier];
Another trouble with the use of two CellIdentifier's in one UITableView is that row height and/or section height have to be taken care of. Two cells can have different heights of course.
When registering classes for reuse the code should look different.
The "simple solution" looks also much different when your cells reside inside a Storyboard instead of Xib's. Watch out for the placeholders.
Keep also in mind that interface builder files have version wise variations and need to be set to a version that your targeted OS version supports. Even if you may be lucky that the particular feature you placed in your Xib is not changed since the last IB version and does not throw errors yet. So a Xib made with IB set to be compatible to iOS 13+ but used in a target that is compiled on an earlier version iOS 12.4 will cause also trouble and can end up with Assertion failure.
Ran into this error bc cell re-use identifier was wrong-- a rookie mistake but it happens:
1. Makes SURE cell re-use idenifier has no misspellings or missing letters.
2. Along same line, don't forget capitalization counts.
3. Zeroes are not "O"s (Ohs)

How can I recycle UITableViewCell objects created from a XIB?

I'd like to create custom UITableViewCell using an XIB, but I'm not sure how to recycle it using UITableViewController's queueing mechanism. How can I accomplish this?
Folks, this question was intended to be self answered as per the FAQ, although I love the awesome responses. Have some upvotes, treat yourself to a beer. I asked this because a friend asked me and I wanted to put it up on StackOverflow. If you have anything to contribute, by all means!
If you're using iOS 5 you can use
[self.tableView registerNib:[UINib nibWithNibName:#"nibname"
bundle:nil]
forCellReuseIdentifier:#"cellIdentifier"];
Then whenever you call:
cell = [tableView dequeueReusableCellWithIdentifier:#"cellIdentifier"];
the tableview will either load the nib and give you a cell, or dequeue a cell for you!
The nib need only be a nib with a single tableviewcell defined inside of it!
Create an empty nib and add the table cell as the first item. In the inspector, you can add the reuseIdentifier string in Interface Builder.
To use the cell in your code, do this:
- (UITableViewCell *)tableView:(UITableView *)_tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *reuseIdentifier = #"blah"; //should match what you've set in Interface Builder
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:reuseIdentifier];
if (cell == nil)
{
cell = [[[NSBundle mainBundle] loadNibNamed:#"YourTableCellNib" owner:nil options:nil] objectAtIndex:0];
}
//set up cell
return cell;
}
There is another method where you create an outlet for your cell and load the cell nib using the controller as the file's owner, but honestly this is much easier.
If you want to be able to access the subviews you've added to the cell in the nib, give them unique tags and access them with [cell viewWithTag:x];
If you want to be able to set custom properties on the cell, you'll need to create a custom UITableViewCell subclass, then just set that as the class of your nib in InterfaceBuilder and cast the UITableViewCell to your custom subclass when you dequeue it in the code above.
To set up a custom UITableViewCell using a XIB, you have to do several things:
Set up an IBOutlet in your header
Configure the table view cell in Interface Builder
Load the XIB inside of tableView:cellForRowAtIndexPath:
Configure it like any other cell
So... Let's set up an IBOutlet in the header file.
#property (nonatomic, retain) IBOutlet UITableViewCell *dvarTorahCell;
Don't forget to synthesize it inside the implementation file.
#synthesize dvarTorahCell;
Now, let's create and configure the cell. You want to pay attention to the Cell Identifier and the IBOutlet as shown below:
Now in code, you load up the XIB into your cell as shown here:
Notice that the Cell Identifier in Interface Builder matches the one shown in the code below.
Then you go ahead and configure your cell like any other.
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) {
[[NSBundle mainBundle] loadNibNamed:#"YUOnlineCell" owner:self options:nil];
cell = dvarTorahCell;
dvarTorahCell = nil;
}
//configure your cell here.
Just note that when accessing subviews, such as labels, you now need to refer to them by tag, instead of by property names, such as textLabel and detailTextLabel.
Here how you can do:
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
YourCustomeCell *cell = (YourCustomeCell *)[tableView dequeueReusableCellWithIdentifier:CellClassName];
if (!cell)
{
NSArray *topLevelItems = [cellLoader instantiateWithOwner:self options:nil];
cell = [topLevelItems objectAtIndex:0];
}
return cell;
}
Where cellLoader in .h is defined as follow:
UINib *cellLoader;
and in .m is istantiated as follows (for example during initialization):
cellLoader = [[UINib nibWithNibName:CellClassName bundle:[NSBundle mainBundle]] retain];
and CellClassName is the defined in .m as follows (is also the name for your xib).
static NSString *CellClassName = #"YourCustomeCell";
Do not forget to use the string CellClassName also in your xib created cell.
For further info I suggest you to read this fantastic tutorial creating-a-custom-uitableviewcell-in-ios-4.
Hope it helps.
P.S. I suggest you to use UINib because is an optimized method to load xib files.

Resources