Memory problem with basic UITableView when scrolling - iphone

I have a very simple UITableView that has 3 sections, and 3 rows per section.
#pragma mark -
#pragma mark UITableView delegate methods
- (NSInteger)tableView:(UITableView *)tblView numberOfRowsInSection:(NSInteger)section
{
return 3;
}
- (UITableViewCell *)tableView:(UITableView *)tblView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tblView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
// Configure the cell...
return cell;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tblView
{
if (tblView == self.tableView) {
return 3;
}
else {
return 1;
}
}
Everything shows up fine, but as soon as I scroll my application crashes and my debugger tells me:
***** -[ProfileViewController tableView:cellForRowAtIndexPath:]: message sent to deallocated instance 0x5ae61b0**
I'm not exactly sure what I am doing wrong.
EDIT:
This is how I am displaying the ProfileViewController:
ProfileViewController* profileView = [[ProfileViewController alloc] initWithNibName:#"ProfileViewController" bundle:nil];
profileView.user_name = username;
profileView.message_source = messageSource;
[self.navigationController pushViewController:profileView animated:YES];
[profileView release];

Looks like your ProfileViewController instance is getting deallocated somehow. Make sure you're not calling its -autorelease after creating it.

Your code seems right. Your bug might be in your model or in the cell configuration. Turn on zombie support for search this kind of error.

something that helped me a similar problem was realizing the following: you may need to retain a table view controller by setting it up as an IBOutlet if it is a subview of another view - i.e. the parent must, in some way, be retaining the child.

Instead of using
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
please use
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
And change your implementation code as follow:
Don't use the below code in "cellForRowAtIndexPath" method. Instead use in "didSelectRowAtIndex" method.
In header(.h) file:
ProfileViewController* profileView;
In implementation (.m) file:
if(profileView==nil)
profileView = [[ProfileViewController alloc] initWithNibName:#"ProfileViewController" bundle:nil];
profileView.user_name = username;
profileView.message_source = messageSource;
[self.navigationController pushViewController:profileView animated:YES];

Related

UITableView reloadData crash

I added CustomImageView to the UITableViewCell.
UITableViewCell *cell = nil;
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"Cell1"] autorelease];
}
CustomImageView *customIV = [[CustomImageView alloc] init];
[cell.contentView addSubView:customIV];
[customIV release];
But when I try to reload tableview, the error occurs.
error call stack is same as follows.
Output string is as follows.
-[CustomImageView superview]: message sent to deallocated instance 0x1f848f30
CustomImageView *customIV = [[CustomImageView alloc] initWithFrame:CGRectMake(x, y, w, h)];
[cell.contentView addSubView:customIV];
It's done with me when I've released memory.
So according to me, No need to release, because it'll deallocated memory.
Hopefully, it'll help you.Thanks.
Try to Comment this line[customIV release]; & run , it should not crash while reloading data.
The reason behind this is everytime it tries to create new custom view & releases it, so causes extra load on system & crash occurs.
You only want to add the image once to each cell. Change your code to this:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell1"];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"Cell1"] autorelease];
CustomImageView *customIV = [[CustomImageView alloc] init];
[cell.contentView addSubView:customIV];
[customIV release];
}
return cell;
}
If this doesn't work then you need to show your complete cellForRowAtIndexPath method. By only showing part of your code you make it difficult to help.
This error occur because each time CustomImageView object created when your cell created.
so, best way is first initialize object of CustomImageView then create your UITableView
such like,
CustomImageView *customIV put it in your .h file and then #synthesize it in .m File
(put this code above UITableView)
self.customIV = [[CustomImageView alloc] init];
Then create UITableView
self.tablView = [[UITableView alloc]init];
.
.
.
.
And in cellForRowAtIndexPath only add [cell.contentView addSubView:self.customIV];

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.

Pushing viewController from a tableview that is inside a viewController not working

I am having an issue pushing my view controller from a tableview that was dropped into a viewController, and not a TableViewController.
I have found a thread on here with a solution here
pushViewController is not pushing
The problem is.. I have done his solution and my view still does not push. I have connected my tableview via ctrl+drag to the view controller and set both the dataSource and delegate. In the post i mentioned, they say the solution was to 'create a referencing outlet from the tableview to the view controller.' But I don't exactly know what that means. So help with that would be good as well. I have followed this tutorial and am stuck on step 9 obviously.
The line of code not triggering is
[self.navigationController pushViewController:facility animated:YES];
My code is as follows...
viewTable methods
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
NSLog(#"list Size: %#",list);
return [list count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = (UITableViewCell *) [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(cell == nil){
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
CustomerListData *customer = [self.list objectAtIndex:indexPath.row];
cell.textLabel.text = customer.facilityName;
// cell.textLabel.text = #"Detail";
return cell;
}
-(void)setValue:(NSMutableArray*)array
{
//NSMutableArray *newArray = [[NSMutableArray alloc] init];
list = array;
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
FacilityMissionListViewController *facility = [self.storyboard instantiateViewControllerWithIdentifier:#"facilityMissionList"];
[self.navigationController pushViewController:facility animated:YES];
//UINavigationController* navController = self.navigationController;
}
the very last commented out line is there to check if navigationcontroller was null. It is not.
From what I have gathered the issue here lies in the fact the table view is inside the view controller and its not a "tableviewcontroller." This method apparently works if that is the case, but some other steps must be taken if not.. but I don't know them.
Thanks in advance.
It sounds like your NavigationController is not set up correctly. Could you post the code that sets it up?
Put a :
NSLog(#"%#", self.navigationController);
in your didSelectRowAtIndexPath method and you'll see if the method is being called and if the navigationController is nil. It might be one of this cases.
Otherwise make sure that the FacilityMissionListViewController is not nil either.

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.

Pull To Refresh on iphone not working as expected

I have been using this: http://blog.leahculver.com/2010/12/iphone-pull-to-refresh.html to make the pull to refresh function in my app.
But I cant see the text "Pull down to refresh...", "Release to refresh..." and "Loading...".
All I've done is copy the files into my project, link against QuartzCore framework, and changed the .h file of my view controller so it is a subclass of PullRefreshTableViewController. Then I added the refresh method.
Is seems that the initWithStyle method in PullRefreshTableViewController never is executed.
But i should be, in my tableViewcellForRowAtIndexPath.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"CellIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
cell.textLabel.text = #"Text";
return cell; }
The initWithStyle method from the PullRefreshTableViewController.m:
- (id)initWithStyle:(UITableViewStyle)style {
self = [super initWithStyle:style];
if (self != nil) {
textPull = [[NSString alloc] initWithString:#"Pull down to refresh..."];
textRelease = [[NSString alloc] initWithString:#"Release to refresh..."];
textLoading = [[NSString alloc] initWithString:#"Loading..."];
NSLog(#"in");
}
NSLog(#"out");
return self; }
The logs are never printed in the console
I really cant see where the problem is ?
Had the same problem.
figured out that not initWithStyle is called instead initWithCoder is called....
so to solve your problem insert following code in your PullRefreshTableViewController.m
and it works like a charm
-(id)initWithCoder:(NSCoder *)aDecoder{
NSLog(#"initWithCoder");
self = [super initWithCoder:aDecoder];
if (self != nil) {
textPull = [[NSString alloc] initWithString:#"Pull down to refresh..."];
textRelease = [[NSString alloc] initWithString:#"Release to refresh..."];
textLoading = [[NSString alloc] initWithString:#"Loading..."];
}
return self;
}
best regards
If you're looking for where the text is defined, it is on Line 43 of the PullRefreshTableViewController.m
Hope this helps (if it does don't forget to vote my answer up)
M.
Try instantiating the PullRefreshTableViewController with:
PullRefreshTableViewController *tableViewController = [[PullRefreshTableViewController alloc] initWithStyle:UITableViewStylePlain];
Instantiating the UITableViewCell using initWithSyle won't have any affect on your UITableViewController subclass.
The alternative is to edit the PullRefreshTableViewController class to override - (id)init method in a similar manner as done with initWithStyle: