TableViewCell subclass not getting initialized - objective-c

I want to create a custom tableViewCell programmatically.
This is what I do:
Creating a tableViewCell subclass and importing it to the tableViewController
In the tableViewController m:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *CellIdentifier = #"StoreCell";
CustomCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
if (cell == nil) {
cell = [[CustomCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
return cell;}
In the CustomCell m:
-(id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
NSLog(#"Hello!");
}
return self;
}
(Sorry for not getting the code highlighting thing to work)
My problem is that the CustomCell don't get initialized. The initWithStyle never gets triggered. I followed a couple of tutorials and they do the exact same thing, but successfully..

With iOS 6, dequeReusableCellWithIdentifier:forIndexPath: always returns a cell, so your if-case never gets called.
If a cell with that identifier is not available, it initializes it itself.
Try implementing initWithCoder: in the UITableViewCell subclass, that's what gets called in that case.

In cellForRowAtIndexPath try this
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"StoreCell";
CustomCell *cell = (CustomCell*)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[CustomCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
return cell;
}

I finally figured it out. The cells didn't get initialized because I was using prototypes cells in the storyboard. I set the prototypes cells to 0 and it works :)

Related

UITableViewCell : initWithFrame : reuseIdentifier deprecated

I'm having trouble with creating my UITableViewCell since UITableViewCell : initWithFrame : reuseIdentifier is deprecated. Please stay with me, I've looked over other questions about this but couldn't find them helpful. So here is my function.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
MyCellObject *cell = (MyCellObject *)[tableView_ dequeueReusableCellWithIdentifier:#"cellid"];
if (cell == nil) {
cell = [[[ChatCell alloc] initWithFrame:CGRectZero reuseIdentifier:#"cellid"] autorelease];
}
return cell;
}
As I read from other questions, I tried:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
MyCellObject *cell = (MyCellObject *)[tableView_ dequeueReusableCellWithIdentifier:#"cellid"];
if (cell == nil) {
cell = [[[MyCellObject alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"cellid"] autorelease];
}
return cell;
}
But my cell won't display its text then. I can tap the cell row and it becomes selects, but no visible text. Because my cell text is handled in my MyCellObject and not cell.textLabel.text, I need to init the cell with a frame (initWithFrame), but I also need to init it with an identifier (reuseIdentifier).
Thanks!
EDIT: I don't think MyCellObject as everything worked before the above function was deprecated. Here's part of MyCellObject and it is derived from UITableViewCell:
- (id)initWithFrame:(CGRect)frame reuseIdentifier:(NSString *)reuseIdentifier {
self = [super initWithFrame:frame reuseIdentifier:reuseIdentifier];
if (self == nil) {
return nil;
}
tagLabel = [[UILabel alloc] initWithFrame:CGRectZero];
tagLabel.backgroundColor = [UIColor clearColor];
tagLabel.font = [UIFont systemFontOfSize:14];
tagLabel.lineBreakMode = UILineBreakModeWordWrap;
tagLabel.opaque = YES;
[self addSubview:tagLabel];
}
The reason I have it setup that was is so I can "micro manage" the text in it a little more.
1) You haven't set the cell title. So you won't see any text on the cell. Here you have used a UITableViewCell class. So you will need to add a label to the cell in the storyboard and set outlet to UITableViewCell in your case which is MyCellObject class. Then you will be able to set text to that label.
2) You can just use
MyCellObject *cell = (MyCellObject *)[tableView dequeueReusableCellWithIdentifier:#"cellid"];
Try this..
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
MyCellObject *cell = (MyCellObject *)[tableView dequeueReusableCellWithIdentifier:#"cellid"];
cell.myCustomLabel.text = #"Your text";
return cell;
}

How to return new allocated object in function on Objective-C?

How to return new allocated object in function?
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"liteCell"];
[cell.textLabel setText:#"Lite"];
return cell; // Object returned to caller as an owning reference (single retain count transferred to caller)
}
Object leaked: object allocated and stored into 'cell' is returned from a method whose name ('tableView:cellForRowAtIndexPath:') does not start with 'copy', 'mutableCopy', 'alloc' or 'new'. This violates the naming convention rules given in the Memory Management Guide for Cocoa
You should return an autoreleased object in this case, so the solution is
UITableViewCell *cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault] autorelease];
Oh, and a better way is to also use [tableView dequeueReusableCellWithIdentifier:CellIdentifier], like this:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"CellIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (nil == cell) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
return cell;
}
For iOS 5 you need to check wether cell is already instantiated, if not you need to instantiate the cell:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"CellIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (nil == cell) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
return cell;
}
Under iOS 6+ you just need to register the Cell you want for the table view like that:
[tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:cellIdentifier];
Then later on you can use:
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath];
and will always receive a allocated cell so you can just write
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"CellIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
return cell;
}

iOS 5, Storyboards, ARC: UITableview doesn't get populated with data from custom delegate and datasource

This is my first time I am working on UITableView connected to custom delegate and datasource. Until today, I used to connect to "self". The prequel for this question is here.
So, I have two additional UIViews. Using segmented control I put one of the over mentioned UIViews on self.view...
Have created two UITableView subclasses and set them as delegate and datasource. Works fine, no leaks or crashes. Checked if the classes getting initialized on segmentedControl index change:
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
NSLog(#"Nominals got init");
}
return self;
}
NSLog works when changing segment.
The question:
In my custom delegate class I override the methods required by UITableViewDelegate and UITableViewDataSource protocols.
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 20;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
UILabel *lbl=[[UILabel alloc]initWithFrame:CGRectMake(12, 12, 200, 12)];
lbl.text=#"some nominal";
cell.textLabel.text=#"Nominal";
[cell addSubview:lbl];
return cell;
}
At moment I am getting exception:
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'UITableView dataSource must return a cell from tableView:cellForRowAtIndexPath:'
Well, isn't the cell in my custom delegated class is the same cell of my UITableView I've created:
-(void)populateNominals:(int)subCountryID
{
NominalsTableViewDelegate *del=[[NominalsTableViewDelegate alloc]init];
[self setNominalsDelegate:del];
UITableView *nominalsTableView=[[UITableView alloc]initWithFrame:CGRectMake(0, 0, 320, 372) style:UITableViewStylePlain];
[nominalsTableView setDelegate:nominalsDelegate];
[nominalsTableView setDataSource:nominalsDelegate];
[nominalsTableView reloadData];
[self.nominalsView addSubview:nominalsTableView];
}
what's my mistake? Thank you in advance.
You aretrying to dequeue a cell using dequeueReusableCellWithIdentifier. If there is no cell in the queue what happens ? Definitely crash.
So you need to allocate a cell, add this line too:
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(cell == nil)
{
cell = [[UITableViewCell alloc] init];
}
On your tableView:cellForRowAtIndexPath: method, you are missing the case where there are no cells to be dequeued. Take a look at your code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
UILabel *lbl=[[UILabel alloc]initWithFrame:CGRectMake(12, 12, 200, 12)];
lbl.text=#"some nominal";
cell.textLabel.text=#"Nominal";
[cell addSubview:lbl];
return cell;
}
You should do something like:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (!cell) {
cell = [[UITableViewCell alloc] init];
}
UILabel *lbl=[[UILabel alloc]initWithFrame:CGRectMake(12, 12, 200, 12)];
lbl.text=#"some nominal";
cell.textLabel.text=#"Nominal";
[cell addSubview:lbl];
return cell;
}
because by doing that, if you can't dequeue a cell, you're creating a new one.
the dequeueReusableCellWithIdentifier will return UITableViewCell instances when the cells are being reused while scrolling through the tableView.
So add
if (nil == cell)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
You have to use the initWithStyle:reuseIdentifier: which is the designated initializer for tableview cells.

Where to put drawrect in cellforrowatindexpath?

It seems to work much faster to do this:
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
JHomeViewCell *cell = (JHomeViewCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[JHomeViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:CellIdentifier];
cell.cellContent.thumbnailCache = self.thumbnailCache;
}
Entry *entry = [self.resultsController objectAtIndexPath:indexPath];
if (cell.cellContent.entry != entry) {
[cell.cellContent setNeedsDisplay];
}
}
The problem is when an entry is edited, the cell doesn't change. I could check for all elements of the cell, to see if they're different, but is there a better way of doing this? Calling drawrect every time the cell appears slows the app down and seems unnecessary.
If you want to do custom drawing for your tableview cell you have to subclass UITableViewCell (as it looks you have done with JHomeViewCell).
Put drawRect inside of your implementation of JHomeViewCell
#implementation JHomeviewCell
- (void)drawRect:(CGRect)rect
{
[super drawRect];
// Insert drawing code here
}
#end
Also, you shouldn't call drawRect directly. You should call setNeedsDisplay instead, and probably need to set the cellContent.entry value to the entry you have from your results controller.
Entry *entry = [self.resultsController objectAtIndexPath:indexPath];
if (cell.cellContent.entry != entry) {
cell.cellContent.entry = entry;
[cell setNeedsDisplay];
}

Return a custom cell from cellForRowAtIndexPath:

I ran into a trouble and I'm looking for help.
I need to save a identifier in a cell, so I did a subclass
of UITableViewCell and added to it the identifier property. In my view
controller I create the cells as follow:
- (SidebarCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell* tableViewCell = [super tableView:tableView cellForRowAtIndexPath:indexPath];
SidebarCell * cell = (SidebarCell *)tableViewCell;
Category *category = [categoryDataController.categories objectAtIndex:indexPath.row];
cell.textLabel.text = category.name;
if (category.checked == 1) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
} else {
cell.accessoryType = UITableViewCellAccessoryNone;
}
return cell;
}
The problem is that when I select one of the cells, the method
cellForRowAtIndexPath: returns an UTableViewCell object instead
of a SidebarCell, so I don't have access to the identifier property:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:[tableView indexPathForSelectedRow] animated:NO];
SidebarCell *cell = (SidebarCell *)[tableView cellForRowAtIndexPath:indexPath]; // Trying to cast from UITableViewCell to SidebarCell
if (cell.accessoryType == UITableViewCellAccessoryNone) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
[CategoryDataController updateRow:cell.identifier status:1]; // Here the app crashes
} else if (cell.accessoryType == UITableViewCellAccessoryCheckmark) {
cell.accessoryType = UITableViewCellAccessoryNone;
[CategoryDataController updateRow:cell.identifier status:0];
}
}
is there a way for cellForRowAtIndexPath: to return an Sidebarcell object?
Thanks beforehand.
Edit
The SidebarCell.h
#import <UIKit/UIKit.h>
#interface SidebarCell : UITableViewCell
#property (nonatomic) NSInteger identifier;
#end
SidebarCell.m:
#import "SidebarCell.h"
#implementation SidebarCell
#synthesize identifier;
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
return self;
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
[super setSelected:selected animated:animated];
// Configure the view for the selected state
}
#end
The error:
2012-04-24 09:21:08.543 Dongo[2993:11603] -[UITableViewCell identifier]: unrecognized selector sent to instance 0x6d87d50
2012-04-24 09:21:08.571 Dongo[2993:11603] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[UITableViewCell identifier]: unrecognized selector sent to instance 0x6d87d50'
*** First throw call stack:
(0x14b1052 0x1a65d0a 0x14b2ced 0x1417f00 0x1417ce2 0x116bc 0x48e71d 0x48e952 0xd1686d 0x1485966 0x1485407 0x13e87c0 0x13e7db4 0x13e7ccb 0x239d879 0x239d93e 0x3fea9b 0x2e85 0x2715 0x1)
terminate called throwing an exception(lldb)
You should leave the tableView:cellForRowAtIndexPath: method signature intact: it should return (UITableViewCell *) and not your custom cell class. Since your SidebarCell is a subclass of UITableViewCell, it should all "just work". No need to call super or any of that:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
SidebarCell *cell = [tableView dequeueReusableCellWithIdentifier:#"CellIdentifier"];
if (cell == nil) {
cell = [[SidebarCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:#"CellIdentifier#"];
}
// ... set up the cell here ...
return cell;
}
In other methods, the cast should work just as you have it:
SidebarCell *cell = (SidebarCell *)[tableView cellForRowAtIndexPath:indexPath];
UITableViewCell* tableViewCell = [super tableView:tableView cellForRowAtIndexPath:indexPath];
The above line of code must be returning a UITableViewCell and not a SidebarCell.
SidebarCell * cell = (SidebarCell *)tableViewCell;
Then on your second line you cast the cell to a SidebarCell, but you are simply lying to the compiler and telling it that it should be a SidebarCell when it is in fact not. When you cast something it needs to start out as the correct type.
Instead of those two lines, you should be creating an actual SidebarCell. How you do this depends on how you have defined it.
Let me know if it is in a storyboard, xib, or created in code and I can provide an example if needed.
EDIT
Since you are creating the cell in code, you simply need to replace the first two lines in cellForRowAtIndexPath with this:
SidebarCell * cell = [[SidebarCell alloc] init];
Everything else looks like it should work as-is.
In my case i have used custom cell of a class tempTableViewcell
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *identifier = #"cellidentifier";
tempTableViewcell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
if (cell == nil) {
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier];
}
cell.textLabel.text = #"abc";
return cell;
}