bug when" new"custom uitablecellview apprear - iphone

i am using a custom uitablecellview like i used to do .But ,unfortunately ,this time an exception is thrown when a new cell appears.So,the same portion of code have worked perfectly many times before .The only difference is that the quality of images that i put into cells is very high.
Did you have ideas?or should i explain more?
Edit
some code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"CellView";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
[[NSBundle mainBundle] loadNibNamed:#"SPViewControllCell" owner:self options:nil];
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
cell=cellView;
self.cellView=nil;
}
UILabel *itemTitle=(UILabel*)[cell viewWithTag:1];
[itemTitle setFont:[UIFont fontWithName:#"Renaissance" size:24]];
itemTitle.text=[titles objectAtIndex:indexPath.row];
UIImageView *img=(UIImageView*)[cell viewWithTag:2];
img.image=[images objectAtIndex:indexPath.row];
return cell;
}
The exception :
"'NSInvalidArgumentException', reason: '-[UITableViewCell objectAtIndex:]: unrecognized selector sent to instance 0x5f36be0'
"
Thank you.

I'm guessing but is titles an array created with something like:
-(void) viewDidLoad(){
// this will give you an autoreleased object
titles = [NSArray arrayWithObjects:#"Foo",...];
// titles will be released once the current event is handled
// try the alloc/init style method
titles = [[NSArray alloc] initWithObjects:... ];
// this will create an array with the retain count still at 1, thus won't be released
Same goes for images.
What you have is the classic memory management issue where a reference you think points to say an NSArray but in fact that array is long gone and happenes to have be replaced my a some random other object.
For completness:
- (void) viewDidUnload {
// clean up after your self
[titles release];
[images release];
}

From the exception description it seems that you are calling ** objectAtIndex:** method from a UITableViewCell class instance.
My question, in your code, what are the class type of your images and titles ivar?

Related

iPhone:TableView cellForRowAtIndexPath method issue

I am facing a crashing problem in cellForRowAtIndexPath tableview delegate method
#interface EventListView : UIViewController <UITableViewDelegate, UITableViewDataSource>
IBOutlet UITableView *tblView;
NSMutableArray *arr_EventValues,*arr_Event_Details;
NSMutableArray *arr_EventListDetails;
#property(nonatomic, retain)NSMutableArray *arr_EventValues,*arr_EventListDetails, *arr_Event_Details;
#property(nonatomic, retain)UITableView *tblView;
- (void)viewDidLoad
{
appdelegate = (VibesGuideAppDelegate *)[[UIApplication sharedApplication] delegate];
ViewCalendar = [[CalendarView alloc] initWithNibName:#"CalendarView" bundle:[NSBundle mainBundle]];
[self.navigationController.navigationBar setHidden:YES];
self.arr_Event_Details = [[NSMutableArray alloc] init];
self.arr_EventValues = [[NSMutableArray alloc] init];
[super viewDidLoad];
}
// Customize the number of sections in the table view.
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
// Customize the number of rows in the table view.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if ([self.arr_EventListDetails count] > 0)
{
return [self.arr_EventListDetails count];
}
return 0;
}
-(UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
// ------------------------------- Custom cell ------------------------------
Customcell *cell = (Customcell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
cell = [[[Customcell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
cell.textLabel.text = #"Hello";
return cell;
}
* -[EventListView tableView:cellForRowAtIndexPath:]: message sent to deallocated instance 0x60e01b0 and I used tableview from xib and set all connections and also got arrayvalues in numberOfRowsInSection in method but in cellForRowAtIndexPath method is not called so please give me idea my issue....
Thanks in advance.
At first it seems your some variable gets released. Make sure you have properly allocated it. If you have declared #property for it you better use the variable as self.variable. You can use retain and in case of IOS 5 strong in property declaration.
Just to be sure you can track if any variable gets released via setting NSZombieEnabled to YES. With zombies enabled, messages to deallocated objects will no longer behave strangely or crash in difficult-to-understand ways, but will instead log a message and die in a predictable and debugger-breakpointable way. You can set NSZombieEnabled by the following steps.
Select Product from the menu bar above. Keep alt/option pressed and select "Test..." or "Run...". Go to the Arguments tab, and add NSZombieEnabled YES in the "Environment Variables" section.
Your tableview itself is already released - the error message says that you send the cellForRowAtIndexPath message to a deallocated instance of the table view - so your problem lies somewhere in not retaining or releasing the EventListView and cannot be seen in the code displayed here.
Check this one:
Table DataSource and delegate is set or not.
Used array in cellForRowAtIndexPath is properly set with property and synthesized as well used with self. name.
First of all you dequeue the cell and then create a new one. This is not a good practice, if you are able to dequeue a cell you should not create a new one. You should have something like this:
Customcell *cell = (Customcell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(cell == nil)
{
cell = [[[Customcell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
}
fix this and let me know if you are still running on the same problem.

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;
}

Memory Management in tableviewDataSource

Just a quick question really:
I'm running a method to pull records from an sqlite database into an array, then assigning the contents of that array to an instance variable.
#interface {
NSArray *items;
}
#implementation
// The population method.
-(void)populateInstanceVariable
{
NSMutableArray *itemsFromDatabase = [[NSMutableArray alloc] init];
// Sqlite code here, instantiating a model class, assigning values to the instance variables, and adding this to the itemsFromDatabase Array.
self.items = itemsFromDatabase;
[itemsFromDatabase release];
}
// viewDidLoad is calling the method above
-(void)viewDidLoad
{
[self populateInstanceVariable];
[super viewDidLoad];
}
// TableViewDataSource method - cellforIndexPath
- (UITableViewCell *)tableView:(UITableView *)passedInTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault];
// Load in my model from the instance variable - ***1
MyDataModel *model = [items objectAtIndexPath:indexPath.row];
// Assign the title to the cell from the model data
cell.textLabel.text = model.title;
// This is the part i'm stuck on, releasing here causes a crash!
[model release];
return cell;
}
#end
My question is two fold:
Is what i'm doing to assign data to the instance variable right? and am i managing the memory correctly?
How do i manage the memory for that model item in the tableview datasource? the only way i seem to be able to get it to run smoothly is if i don't release the *model object at all, but that causes leaks surely?
Cheers.
No, you're not managing memory correctly here:
you should use "reusable" UITableViewCells, most UITableView examples show how to do this, and
do not do [model release], you do not "own" the object in this case, you're just referring to it so you must not release it
Here's the typical cellForRowAtIndexPath:
-(UITableViewCell *) tableView:(UITableView *)atableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"CellIdentifier";
// Dequeue or create a cell of the appropriate type.
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier] autorelease];
// settings that do not change with every row
cell.selectionStyle = UITableViewCellSelectionStyleGray;
}
// settings that change with every row
cell.textLabel.text = #"fill in your label here";
return cell;
}
Also, if you're using a DB for your data, you may want to look in to Core Data, Apple's data persistence/management framework, it includes the ability to hook aspects of your data entities directly up to UITableViews.
1) Populate method is correct. Don't forget to set the instance variable to nil in the dealloc. (I suppose you added a property/synthesize as you used the 'self.').
2) Do NOT release the model object. You did not retain, copy or allocated it in that method. By the other hand your initialization of the cell is wrong. Use the following: (Better for performance)
- (UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *Identifier = #"CellIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:Identifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:Identifier] autorelease];
}
//Other code
}

iphone how to access a custom cell outside of cellForRowAtIndexPath

i have set up a tableview with custom cells. customCell is a class.
heres the code for a more accurate view:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSManagedObject *object = (NSManagedObject *)[entityArray objectAtIndex:indexPath.row];
NSString *cellIdentifier = [NSString stringWithFormat:#"asd%d", indexPath.row];
customCell *cell = [[tableView dequeueReusableCellWithIdentifier:cellIdentifier] autorelease];
//i tried setting a tag but dunno how to call it afterwards
[cell setTag:indexPath.row];
if (cell == nil) {
NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:#"customCell" owner:self options:nil];
cell = [topLevelObjects objectAtIndex:0];
}
if (cell.imagen != nil) {
[[cell imageView] setImage:[cell imagen]];
} else { /* setup image... */ }
}
-(void) webImageReady:(WebImage *)downloadedImage imageView:(UIImageView *)imageView cellTag:(NSInteger *)cTag
{
// This is the part where i want to access cell.imagen, this is actually wrong...
[[[imageView.superview viewWithTag:cTag] imagen] setImagen:downloadedImage.Image];
[imageView setImage:downloadedImage.Image];
}
Ok. now i want to access (reference) the cell.imagen property from a method outside cellForRowAtIndexPath, more precisely at a selector for a download finished (delegated)
Thanks in advance!
Do it inside cellForRowAtIndexPath if the image is downloaded, and on successful download of the image do [tableview setNeedsDisplay]
You shouldn't refer to the cell outside the cell creation method, you should consider the case the cell was rendered but while getting the image was scrolled out the dealloced or even reused for another cell, one way to solve it is to have image view array or something similar.
I think you should try using a third party lib that already doing it(among other things) called Three20. It have an object call TTImageView that gets a URL and loads it in the background, it solves all of the cases along with optimized caching

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.