Custom cell just failing - iphone

I'm trying to use a custom UITableViewCell, and I've placed it in the same nib file as the UITableView controller. For this, the files are: NTItems.h, NTItems.m and NTItems.xib.
I have defined the cell in the header file:
IBOutlet UITableViewCell *cellview;
and I've correctly applied the property: nonatomic, retain so it's there:
#property (nonatomic, retain) IBOutlet UITableViewCell *cellview;
In the m file - I've synthesized the variable device and am using this to get the custom cell:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"cellview";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = self.cellview;
}
Product *aProduct = [appDelegate.products objectAtIndex:indexPath.row];
name.text = aProduct.name;
upc.text = [NSString stringWithFormat:#"UPC%#",aProduct.upc];
price.text = aProduct.pid;
return cell;
}
However, when I load the table, I get this horrible mess:
alt text http://dl.dropbox.com/u/1545603/tablecellissue.png
There should be more than 1 cell showing data as well. It appears that only the last data is showing up right now.

You can't reuse a single cell from an outlet like this. Think about it: you're returning the same cell for every call to tableView:cellForRowAtIndexPath:. It's your job to ask the tableView to dequeue a cell if possible, and create a new one each time it isn't.
Instead, store your custom cell in a separate nib and read that nib within your if (cell == nil) { } code when dequeue fails.
The nib file that contains the custom cell should have its File's Owner NSObject and it should contain only the cell's nib (no other objects).
I use this function to load the nib:
- (id)loadObjectFromNibNamed: (NSString *)inName;
{
id objectsInNib = [[NSBundle mainBundle] loadNibNamed: inName
owner: self
options: nil];
NSAssert1( objectsInNib != nil, #"loadNibNamed %# returned nil", inName );
NSAssert2( [objectsInNib count] == 1, #"lodNibNamed %# returned %d items", inName, [objectsInNib count] );
return [objectsInNib objectAtIndex: 0];
}
Then in my tableView:cellForRowAtIndexPath: I have:
if ( cell == nil ) {
cell = [self loadObjectFromNibNamed: nibName];
}
(I use the same nib name as my cell reuse identifier.)

What's happening is that you're only using one cell for the entire table. That means that the last cell drawn is the only visible one. The prior cells essentially don't exist.
You will want to review this document on how to create custom table view cells from a NIB.
There are step by step instructions there.

Related

Dealloc of custom cell loaded from NIB is not called

So I have a subclass UITableViewCell named MCProductCell, which is loaded from a NIB. The problem is that when the table is released, the dealloc method of my custom cell is not called even once.
Here is some sample code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = #"MCProductCellIdentifier";
MCProductCell *cell = (MCProductCell *)[tableView dequeueReusableCellWithIdentifier:cellIdentifier];
// Boolean value needed to determine if it is a reused cell or not. If it's not reused we have
// to start the thread that loads the image. For reused cells, that thread is started at the
// end of the scrolling
BOOL recycled = YES;
if (cell == nil) {
NSLog(#"cell alloc");
recycled = NO;
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"MCProductCell" owner:self options:nil];
cell = [nib objectAtIndex:0];
}
MCProduct *product = [products objectAtIndex:indexPath.row];
cell.product = product;
cell.cartViewController = self;
cell.productImage = product.cachedThumbnailImage;
if (product.cachedThumbnailImage == nil) {
cell.productImage = [ViewControllerUtils getDefaultImage];
if (!recycled)
[NSThread detachNewThreadSelector:#selector(loadImage:) toTarget:cell withObject:cell.product.imageThumbnailUrl];
}
return cell;
}
And for some reason, when I first present my UIViewController, that contains the table, the dealloc method of my custom cell is called ONCE.
The problem is that in the dealloc method I want to remove the cell as an observer, and if it isn't called, then the cell isn't removed as an observer.
Also the tableview is an outlet.
I figured out, it must be because the retain count of the cell is not going down to 0.
Which means you have another retain.
My more experienced colleague thinks its because you are using the detachNewThreadSelector, which probably retains the cell.
He suggested you would load the image by using some type of asynchrony image such as
https://github.com/nicklockwood/AsyncImageView/
Good luck.
How is the 'cell.cartViewController' property defined? If it's retaining your controller object (self), then you probably have a retain cycle in there!

How do I populate tableview using cell?

to the point, i have custom cells, inside it has 2 label and 1 textfield. both label and textfield got input from user. i also have other view that has uitableview inside it. my question is how do i populate cell in uitableview? please help.
this is my code inside tableviewcontroller.
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 1; // i want to populate this using 'count' but i dont know how.
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
CustomCell *cell = (CustomCell *)[tableView dequeueReusableCellWithIdentifier:[CustomCell reuseIdentifier]];
if (cell == nil)
{
[[NSBundle mainBundle] loadNibNamed:#"CustomCell" owner:self options:nil];
cell = _customCell;
_customCell = nil;
}
cell.titleLabel.text = [NSString stringWithFormat:#"%#",titleTextString];
cell.timerLabel.text = [NSString stringWithFormat:#"%#",timerString];
cell.statusLabel.text = [NSString stringWithFormat:#"%#",statusString];
return cell;
}
how do i populate my tableview if i push add button after finishing input by user? Please if you dont mind help me with code. i'm beginner and im hard to understand by using opinion.
If I understood your question correctly, you did a custom nib file for your cells that has 2 UILabel in it and one UITextField, and you want to access these objects when populating your table. Here are some steps for this issue:
First, you have to give a tag number for each object in your custom cell. You find this property in the Attribute Inspector in Interface Builder. Say you gave the first label tag 1, the second label 2 and the text field 3.
Second you have to give a. Identifier for this nib file, for example MyCustomCellIdentifier. This identifier will be used later on in the view that has the table so you can link to it.
Third, also in the custom cell nib, you click on the yellow square that says File's Owner and in the Identity Inspector you change the Class to the class name that has the table that will use this custom cell.
Fourth, in the class that you have the table that will use the custom cell, create an outlet of type UITableViewCell. We will link this in the custom nib cell.
Fifth, goto the custom nib cell, click on the cell window, then in the Connections Inspector link New Referencing Outlet to the File's Owner, you will see the outlet that you created in the table class showing here, simply link to it.
Now since the connections are established thing are more easy, in the cellForRowAtIndexPath function (in the class that contains the table for sure), you have to load the custom cell from the nib file as follows:
static NSString *tableIdentifier = #"MyCustomCellIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:tableIdentifier];
if(cell == nil)
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"TheNibClassNameOfYourCustomCell" owner:self options:nil];
if([nib count] > 0) cell = theNameOfTheOutletYouUsed;
else NSLog(#"Failed to load from nib file.");
}
Ok, your custom cell is loaded in variable cell, now you have to access every object in it from the tags you created:
UILabel *label1 = (UILabel *)[cell viewWithTag:1];
UILabel *label2 = (UILabel *)[cell viewWithTag:2];
UITextField *textField1 = (UITextField *)[cell viewWithTag:3];
Now you can access everything through label1, label2, and textField1 easily like label1.text = #"Hi";
I hope this answers your question.

Unable to flush reusable UITableViewCell data

I have a UITableView with a custom UITableViewCell.
-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
//create the cell
MyCell *cell = (MyCell*)[tableView dequeueReusableCellWithIdentifier:#"MyIdentifier"];
cell.label.text = ..
cell.label2.text = ..
cell.label3.text = ..
Everything works fine, all my data loads properly, etc.
Now, I have a button on this View Controller that opens another view where the user can select which labels to display. So, for instance, display labels 1 and 3, but not 2...
Then, when Done is clicked, I want the tableView to be updated to reflect the new options, but since the cells were loaded with a reuseCellId, no changes are shown. How can I force the cells to recreate?
I thing that the best thing you could do is to store the cells configuration in some kind of structure (a set with the labels indices to be shown would be ok here) and alter this structure with your buttons and reload the table view. Then, on your tableView:cellForRowAtIndexPath: method, you should check that configuration structure in order to know what buttons should be visible.
This code may help:
#interface MyViewController : UIViewController
{
...
NSMutableSet *_labelsToShow;
}
...
#property (nonatomic, retain) NSMutableSet labelsToShow
#end
#implementation MyViewController
#synthesize labelsToShow = _labelsToShow;
- (void)dealloc
{
[_labelsToShow release];
...
}
//you may know which button has to add/remove each label, so this needs to be fixed with your logic
- (IBAction)myButtonAction:(id)sender
{
if (hasToShowLabel)
{
[self.labelsToShow addObject:[NSNumber numberWithInteger:labelIdentifier]];
} else
{
[self.labelsToShow removeObject:[NSNumber numberWithInteger:labelIdentifier]];
}
}
-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = #"myCell";
MyCustomCell *cell = (MyCustomCell *)[tableView dequeReusableCellWithIdentifier:cellIdentifier];
if (cell == nil)
{
cell = [[[MyCustomCell alloc] initWithStyle:UITableViewCellStyleDefault] autorelease];
}
cell.label0.hidden = (![self.labelsToShow containsObject:[NSNumber numberWithInteger:0]]);
cell.label1.hidden = (![self.labelsToShow containsObject:[NSNumber numberWithInteger:1]]);
cell.label2.hidden = (![self.labelsToShow containsObject:[NSNumber numberWithInteger:2]]);
...
return cell;
}
#end
Good luck with this!
This is NOT a good approach
One way you can do this by using different identifier when you want to refresh cells
I am not sure if there is any other better way of doing this.
I solved this issue by just destroying the tableview, and recreating it every time.

custome UITableview calling methods to store value in cell in iphone

I am using custom UITableview concept to show data in cell of tableview. My custome uiTableview name is CustomeUITableView.h,CustomeUITableView.m and CustomeUITableView.xib file. This file is consisting following code.
//header file code
#interface CustomTableCellview : UITableViewCell {
UILabel *titleOfPost;
IBOutlet UILabel *userProfileName;
}
#property(nonatomic,retain) IBOutlet UILabel *titleOfPost;
- (void)setTileOfPost:(NSString *)_text;
- (void)setUserName:(NSString *)_text;
#end
// some important part of class file code
- (void)setTileOfPost:(NSString *)_text{
titleOfPost.text = _text;
}
- (void)setUserName:(NSString *)_text{
userProfileName.text = _text;
}
// TableView code where cell is creating and function of cutome UITableview is calling
static NSString *MyIdentifier = #"MyIdentifier";
MyIdentifier = #"tblCellView";
CustomTableCellview *cell = (CustomTableCellview *)[tableView dequeueReusableCellWithIdentifier:MyIdentifier];
if(cell == nil) {
[[NSBundle mainBundle] loadNibNamed:#"CustomTableCellview" owner:self options:nil];
cell = tblCell; //IBOutlet CustomTableCellview *tblCell;
}
[cell setTileOfPost:[tableList objectAtIndex:indexPath.row]];
[cell setUserName:[profileUserName objectAtIndex:indexPath.row]];
return cell;
This is calling well and my output is displaying data fine. But here is a bit mistake. I am calling function "setTileOfPost" and "setUserName" in each CELL load. This is making large function calling. I want to fetch all title of text in one call of function. I don't want to use calling function again and again. I stored value in "tableList" and this is extern array defined in main.m file so I can use this array anywhere in application.
How to grab all value in single function call?
Thanks in advance
tableList and profileUserName are of type NSArray or NSMutableArray i suppose. What you can do is in your viewdidLoad method create a copy of these arrays as the data source.
And in cellforrowatindexpath you can directly access these copies.
[cell.title setText:[tableListCopy objectAtIndex:indexPath.row]];
I hope you get the point here. You are having a local copy of the datasource of the tableview.

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.