custom tableviewcell is nil - iphone

I have a table and I want to fill it with custom tableViewCells, in order to provide the user with information on orders. The problem is that the tableview shows the cells but does not fill them with the information I need. When I inserted breakpoints, I found out that the cells are nill, not matter what I do. this is my cellForRowAtIndexPath:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
OrderOverViewCell *cell = (OrderOverViewCell *)[tableView dequeueReusableCellWithIdentifier: #"orderOverviewCell"];
OrderClass *orderClass = nil;
if (filteredArray == nil) {
if (sortedArray.count >0) {
orderClass = sortedArray[indexPath.row];
}
}
else if (filteredArray != nil) {
orderClass = filteredArray[indexPath.row];
}
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"dd/MM/yyyy HH:mm"];
NSString *orderDate = [dateFormatter stringFromDate:orderClass.orderDate];
cell.orderTitle.text = [NSString stringWithFormat:#"%#%# %#",orderClass.companyName,#",", orderDate];
cell.orderDetail.text = [NSString stringWithFormat:#"%# %# %# %#.", #"order nummer:",orderClass.orderNumber, #"betaling:", orderClass.orderPaymentType];
if ([orderClass.orderDelivery isEqualToString:#"Bezorgen"]) {
cell.orderDelivery.text = [NSString stringWithFormat:#"Levering: Bezorgen op %#, %#, %#", orderClass.orderAdress, orderClass.orderAdressZip, orderClass.orderCity];
}
if ([orderClass.orderDelivery isEqualToString:#"Afhalen"]) {
cell.orderDelivery.text = [NSString stringWithFormat:#"Levering: Afhalen op ingestelde datum en tijd."];
}
cell.orderIndication.image = nil;
if ([orderClass.preparing isEqualToString:#"1"]) {
if ([orderClass.ready isEqualToString:#"1"] ){
if ([orderClass.delivered isEqualToString:#"1"]){
cell.orderIndication.image = [UIImage imageNamed:#"order_3.png"];
}
else {
cell.orderIndication.image = [UIImage imageNamed:#"order_2.png"];
}
}
else {
cell.orderIndication.image = [UIImage imageNamed:#"order_1.png"];
}
}
cell.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"orderCellBG.png"]];
return cell;
}
Does anybody have an idea what i'm doing wrong? any help would be very appreciated.

Add this in viewDidLoad to indicate the cell to use:
UINib *const cell = [UINib nibWithNibName:#"nibName" bundle:[NSBundle mainBundle]];
[_tableView registerNib:cell forCellReuseIdentifier:#"orderOverviewCell"];

If you're defining your custom cell as a Prototype Cell inside a Storyboard, make sure you have assigned the proper identifier (orderOverviewCell)
According to Apple developer docs
Because the prototype cell is defined in a storyboard, the dequeueReusableCellWithIdentifier: method always returns a valid cell. You don’t need to check the return value against nil and create a cell manually.

Couple of things to check! If you are using Storyboards and your cell is a prototype cell which is contained inside a UITableView instead of a separate Nib file then make sure the unique identifier is correct.
The case as well as spelling matters so make sure you have named the "orderOverviewCell" correctly in the code as well as in the storyboard when you click on the cell.
OrderOverViewCell *cell = (OrderOverViewCell *)[tableView dequeueReusableCellWithIdentifier: #"orderOverviewCell"];
The above code will instantiate the cell and return a valid cell so you don't need to check for nil or anything. I am also assuming that you are using UITableViewController and not a ViewController with a UITableView as an outlet.

changing it to this solved it:
OrderOverViewCell *cell = (OrderOverViewCell *)[self.tableView dequeueReusableCellWithIdentifier: #"orderOverviewCell"];

Related

iPhone sdk UITableView cell reuse identifier

I am using UITableView. When a book is downloaded i am adding a checkmark image to my table. And i have done this. But when am scrolling my table am getting the image even for non-downloaded books (i.e) my table cell are reused. For this i googled and checked my code with that. Everything seems to be the same. Here is my code,
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UIImage *cellImage= [cacheImage getCachedImage:[listOfThumImages objectAtIndex:indexPath.row]];
if(cellImage == nil)
{
DeviantDownload *download;
download = [DownloadsArray objectAtIndex:indexPath.row];
cellImage = download.image;
if (cellImage == nil)
{
download.delegate = self;
}
NSLog(#"cellImage%#",cellImage);
UIImageView *imgView;
static NSString *CellIdentifier = #"";
cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
imgView1 = [[UIImageView alloc] initWithFrame:CGRectMake(680, 60, 40, 40)];//self.view.bounds.size.width-
[imgView1 setImage:[UIImage imageNamed:#"Downloaded.png"]];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
if([defaults objectForKey:#"firstRun"])
{
if([[[appDelegate selectDB] valueForKey:#"bookname"] containsObject:[listOfBooks objectAtIndex:indexPath.row]] )
{
NSString *cellValue = [listOfBooks objectAtIndex:indexPath.row];
cell.contentView addSubview:imgView1];
}
return cell;
}
}
}
What's wrong with my code? Kindly help me out. Thanking You.
If you want that a cell does not display the image then simply remove the imageview, for that cell. set a view.tag for the image view, and retrieve it, then remove it.
What you are doing now, is to add a image sub view as soon as you need it for a cell, and later reuse that cell for all other rows. But you never removed the imageview for cells that dont need it.
CheckMarks with UITableView is little complicated then what it seems. First of all you'll have to save the status of your row which already has the bookmark. And, compare it in your cellForRowAtIndexPath method. What you can do is create on NSMutableArray. Save 1 for downloaded book and 0 for non-downloaded book. In your cellForRowAtIndexPath method compare [array objectAtIndex:indexpath.row] and set the image accordingly.
Also, change :
static NSString *CellIdentifier = #"";
To :
static NSString *CellIdentifier = #"MyCell";

Custom UITableViewCell does not show the labels in storyboard

In this screen shot you can see that I have added UITableView in UIViewController then customized the UITableViewCell by adding some labels in it. But the issue is when I run the application. All of the cells are empty. There are no labels at all.
I am not getting what can be the issue. I have searched the web and read tutorials but couldn't resolve it.
I resolved this issue by myself, just after little effort.
Actually 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;
}
I did this all and my issue was resolved and please don't forget to connect the delegates & datasource and table.
Hope this will help others.
It is little bit late but you can solve your problem by setting the background color of your view as Clear Color from your storyboard.
in the tableview's delegate method , cellforrowatindexpath has a uitableviewcell inside it , there should be an identifier in the initialization of this cell. possibly it is "cell" or "cellIdentifier" .
you just need to select your cell from storyboard and enter this identifier string to the storyboard , where uitableviewcell's attribute inspector stays.
hope this helps.. :)
First Set cell identifier in storyboard #"Cell"
then set tag of label
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
// Create
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] ;
}
UILabel *lblDate = (UILabel*)[cell viewWithTag:101];
UILabel *lblDistance = (UILabel*)[cell viewWithTag:102];
UILabel *lbltype = (UILabel*)[cell viewWithTag:103];
lblDate.text = [temp objectAtIndex:indexPath.row] valueForKey:#"date"] stringByReplacingOccurrencesOfString:#"-" withString:#"/"]];
lblDistance.text = [NSString stringWithFormat:#"%# KM",[[temp objectAtIndex:indexPath.row] valueForKey:#"distance"]];
NSString *type = [NSString stringWithFormat:#"%#",[[temp objectAtIndex:indexPath.row] valueForKey:#"distance"]];
if([type isEqualToString:#"0"])
{
lbltype.text = #"Personal";
}
else
{
lbltype.text = #"Bussiness";
}
// Configure
return cell;
}

UITableView not refreshed

I have an app consisting of a TabBar with a few TabBarControllers. One Controller contains a very simple table, which is supposed to display the contents of a NSMutableDictionary. When you hit the appropriate button, the Dictionary is updated in a separate Controller and the view switches to the UITableViewController, displaying the newly updated table.
I can see the Dictionary being updated. But the TableView never reflects the changes. In fact, it seems to display the changes only the 1st time I enter that screen.
I have tried [self table.reloadData] and while it gets called, the changes aren't reflected to the UITableView.
Does anyone have any suggestions? I am happy to post code, but am unsure what to post.
Update: the table is updated and refreshed properly only the 1st time it is displayed. Subsequent displays simply show the original contents.
Background:
The tableview gets filled from a dictionary: appDelegate.currentFave. The tableview should get refreshed each time the ViewController is invoked by the TabBarController.
- (void)viewWillAppear:(BOOL)animated
{
NSLog(#"in viewWillAppear");
[super viewWillAppear:animated];
[self loadFavesFile];
[self.tableView reloadData];
}
// load the Favorites file from disk
- (void) loadFavesFile
{
// get location of file
NSString *path = [self getFavesFilePath];
// The Favorites .plist data is different from the Affirmations in that it will never be stored in the bundle. Instead,
// if it exists, then use it. If not, no problem.
if ([[NSFileManager defaultManager] fileExistsAtPath:path]) {
// read Faves file and store it for later use...
NSMutableDictionary *tempDict = [NSMutableDictionary dictionaryWithContentsOfFile:path];
appDelegate.sharedData.dictFaves = tempDict;
// grab the latest quote. Append it to the list of existing favorites
NSString *key = [NSString stringWithFormat:#"%d", appDelegate.sharedData.dictFaves.count + 1];
NSString *newFave = [NSString stringWithFormat:#"%#", appDelegate.currentFave];
[appDelegate.sharedData.dictFaves setObject:newFave forKey:key];
} else {
NSLog(#"Favorites file doesn't exist");
appDelegate.sharedData.dictFaves = nil;
}
}
// this gets invoked the very first call. Only once per running of the App.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// reuse or create the cell
static NSString *cellID = #"cellId";
UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:cellID];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellID];
}
// allow longer lines to wrap
cell.textLabel.numberOfLines = 0; // Multiline
cell.textLabel.lineBreakMode = UILineBreakModeWordWrap;
cell.textLabel.font = [UIFont fontWithName:#"Chalkduster" size:(16)];
cell.textLabel.textColor = [UIColor yellowColor];
// NOTE: for reasons unknown, I cannot set either the cell- or table- background color. So it must be done using the Label.
// set the text for the cell
NSString *row = [NSString stringWithFormat:#"%d", indexPath.row + 1];
cell.textLabel.text = [appDelegate.sharedData.dictFaves objectForKey:row];
return cell;
}
I found the problem. I was not properly initializing and assignng the TableView in my view controller. See below
- (void)viewDidLoad
{
[super viewDidLoad];
tableView = [[UITableView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame] style:UITableViewStylePlain];
tableView.dataSource = self;
tableView.delegate = self;
tableView.backgroundColor=[UIColor blackColor];
self.view = tableView;
}
Assuming the code you have put up is correct, you want to use [self.table reloadData]. You have the . in the wrong place.
I had this same problem yesterday, for me it turned out I had set the wrong file owner in interface builder and hadn't set up the data source and delegates for the table view properly.
Try going into interface builder and right-clicking on the file owner, this should show you if anything isn't connected up properly.
You should make sure that your Interface Builder connections are set up properly, but what this problem really sounds like is that you have your UITableViewCell setup code in cellForRowAtIndexPath: inside your if(cell == nil) statement. Which it shouldn't be. Let me explain. If you have a list of cells, and you want to set the titles to each cell to a string in an array called myArray, right now your (incorrect) code looks like this:
- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cellIdentifier"];
if (cell == nil) {
// No cell to reuse => create a new one
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:#"cellIdentifier"] autorelease];
[[cell textLabel] setText:[myArray objectAtIndex:[indexPath row]]];
}
return cell;
}
Can you see the problem with that logic? The cell will only get an updated title if no reusable cell can be found, which, in your case, sounds like the situation. Apple says that you should create a 'new' cell each time cellForRowAtIndexPath: is called, which means that you put all of your setup code outside of the if(cell == nil) check.
Continuing with this example, the proper code would look like this:
- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cellIdentifier"];
if (cell == nil) {
// No cell to reuse => create a new one
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:#"cellIdentifier"] autorelease];
}
[[cell textLabel] setText:[myArray objectAtIndex:[indexPath row]]];
return cell;
}
This way, the cell gets assigned the proper string whether or not a reusable cell is found and so calling reloadData will have the desired effect.

Random Debugging / Wrong Memory Management

I have no idea what's wrong with my program...
I think something bad with the memory management, cos every time I try to execute the app i have a different result from the simulator.
When I run the app everything works fine. The date formatter works fine! I can see in the table all the cell formatted in the right way!
The interface is a tabController whit 2 tableView to show the content of a database and a tab with a view used to add element to the db.
If I go in the "Add Tab" i can add all the element I want, but when i switch back to the others tab the program crash with an "Exe_Bad_Access" (in the code below).
- (UITableViewCell *)tableView:(UITableView *)_tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [_tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
[[NSBundle mainBundle] loadNibNamed:#"MovieTableCell" owner:self options:NULL];
cell = nibLoadedCell;
}
// Configure the cell.
UILabel *itemLabel = (UILabel *) [cell viewWithTag:1];
UILabel *priceLabel = (UILabel *) [cell viewWithTag:2];
UILabel *groupLabel = (UILabel *) [cell viewWithTag:3];
UILabel *dateLabel = (UILabel *) [cell viewWithTag:4];
NSDictionary *rowVals = (NSDictionary *) [shoppingListItems objectAtIndex:indexPath.row];
NSString *itemName = (NSString *) [rowVals objectForKey:#"item"];
itemLabel.text = itemName;
int groupid = [(NSNumber *) [rowVals objectForKey:#"groupid"] intValue];
groupLabel.text = Group[groupid];
NSNumber *price = (NSNumber *) [rowVals objectForKey:#"price"];
priceLabel.text = [priceFormatter stringFromNumber: price];
NSDate *dateValue = (NSDate *) [rowVals objectForKey:#"dateadded"];
NSString *str = [dateFormatter stringFromDate:dateValue]; //-->Here I got the Bad Access
[dateLabel setText:str];
return cell;
[itemLabel release];
[groupLabel release];
[priceLabel release];
[dateLabel release];
}
Here is the entire program, if someone want to have a look: http://cl.ly/A1yk
3 things:
1) Anything after your return statement will not run. The 4 lines after that will never get run.
return cell;
[itemLabel release];
[groupLabel release];
[priceLabel release];
[dateLabel release];
2) If those release statements did run, the next time you access those labels you will get a bad access error, because those UILabels will get deallocated. Don't call 'release' on any object you haven't called 'retain' on.
3) To understand if anything is wrong with dateFormatter, we'd have to see every piece of code that touches that variable.
Look at the memory management of dateFormatter. It's may be being over released. You can check by adding a
NSLog(#"Date formatter: %#", dateFormatter);
before the string call and see what shows up.
By they way, remove the [itemLabel release] etc. lines. (a) they are not being executed as they follow your return cell and (b) if they were called, they'd cause problems.
Your casting NSDate to the objectAtIndex, are you sure the object is not some other class is it? Also, is the dateFormatter variable initialised as it could be nil?
Try removing the release lines at the end. As you are not allocating the UILabel its better not to release those. Hope this helps!
I cant be sure if this might be the reason, coz exc_bad_access can occur for anything. But it seems like when you are reusing the same cell, you are never allocating it urself but instead getting it as nibloaded cell from the interface builder.
Try using the default code where u alloc/init a cell:
(UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = #"MyCell";
UITableViewCell *cell =
[tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil)
{
cell =
[[[UITableViewCell alloc]
initWithFrame:CGRectZero
reuseIdentifier:cellIdentifier]
autorelease];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
cell.text = label;
return cell;
}

iPhone table view - problem with indexPath.row

I'm using indexPath.row do determine in which row of my tableview I do something. The title of my cells is containing a number which should be 1 in the first row and 18 in the last row, so I have 18 rows. This works for the first 11 rows, but after that, I have numbers in the title which seem to be generated randomly! Sometimes 16, then 5, then 18, then 12... and so on.
What's the problem with it/why does the indexPath.row variable behave like that?
My cellForRowAtIndexPath method:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *MyIdentifier = #"MyIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier];
if (cell == nil) {
[[NSBundle mainBundle] loadNibNamed:#"myCell" owner:self options:nil];
cell = cell0;
self.cell0 = nil;
}
UILabel *label;
label = (UILabel *)[cell viewWithTag:1];
label.text = [NSString stringWithFormat:#"Cell %d", indexPath.row];
return cell;
}
Any more suggestions on how to solve the problem? I didn't get it working until now...
// Update with more code:
Here is how I declare the cell. It is in an XIB file (template "empty XIB") in which I just put the cell from the library in IB.
#interface myViewController : UITableViewController {
UITableViewCell *cell0;
}
#property (nonatomic, retain) IBOutlet UITableViewCell *cell0;
Then, at the top of the myViewController.m file:
#synthesize cell0;
My cellForRowAtIndexPath method is already posted above. It is equal to the cellForRowAtIndexPath method in the SDK documentation, and in Apple's example, it seems to work.
What are you trying to accomplish with cell0?
cell = cell0;
self.cell0 = nil;
It looks like you're creating a new cell, but somehow deciding to use an old one. The real culprit looks like the code that is loading the cell actually getting assigned anywhere.
Try just this instead:
if (cell == nil) {
cell = [[NSBundle mainBundle] loadNibNamed:#"myCell" owner:self options:nil];
}
Or perhaps:
if (cell == nil)
{
// TODO: try to avoid view controller
UIViewController *vc = [[UIViewController alloc] initWithNibName:#"IndividualContractWithResult" bundle:nil];
cell = (IndividualContractWithResult_Cell *) vc.view;
[vc release];
}
To would be easier to answer if you give the code where you create cells for your table view. It looks that there's a problem with reusing cells - you reuse previously created cells without setting a new value to it.
It sounds like you are not re-using cells but creating new ones when there are cells available. Look at the sample code for dequeueReusableCellWithIdentifier.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"MyCell"];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:#"MyCell"] autorelease];
}
cell.text = <your code here>;
return cell;
}
It would seem that you're incorrectly accessing a property here:
cell = cell0;
self.cell0 = nil;
Assuming that you have an instance variable named cell0, by setting it to nil, you may be releasing it before you're ready to use it.
The proper way to do this is:
cell = self.cell0;
self.cell0 = nil;
This way, if cell0 is declared as retain, you'll automatically get an autoreleased cell0 back, whereas if you reference cell0 directly (no self.), you'll get an unretained reference, which will disappear when self.cell0 = nil is called.
The advantage of using a nib-based cell here is that you can use outlets, rather than tags, to identify subviews. You've done the heavy lifting already, you might want to just add an outlet and subclass UITableViewCell to get access to the label.
You will need to retain and autorelease cell0, otherwise when you set self.cell0 = nil, then cell0 has no known references.
cell = [[cell0 retain] autorelease];
self.cell0 = nil;
You can also do this:
cell = self.cell0;
self.cell0 = nil;
.. Since any retain properties should implement their getters with the retain/autorelease pattern.