NSZombie in didSelectRowAtIndexPath - iphone

I have an interesting problem, and I can't seem to find out why it is happening, might be something small that I am overlooking.
I have a UITableView and in my didselectrowatindex path I navigate to a new view, I then navigate to the next view and pop both views to get back to the first and then the app crashes with the EXC_BAD_ACCESS
So I used instruments and NSZombie and found a malloc in didselectrowatindexpath, but I have no idea why
Here is my code:
if([workflowswithdirectories count] == 0)
{
WorkflowViewController *aWorkFlow = [[WorkflowViewController alloc] init];
MenuObject *obj = [workflownames objectAtIndex:[indexPath row]];
aWorkFlow.heading = obj.name;
aWorkFlow.workId = obj.workflowid;
aWorkFlow.siteId = obj.siteid;
aWorkFlow.item = obj;
[self.navigationController pushViewController:aWorkFlow animated:YES];
}
else if([workflownames count] == 0)
{
WorkflowListViewController *work = [[WorkflowListViewController alloc] init];
work.siteId = self.siteId;
MenuObject *obj = [workflowswithdirectories objectAtIndex:[indexPath row]];
work.menu = obj.next;
work.heading = obj.name;
[self.navigationController pushViewController:work animated:YES];
}
else
{
if([indexPath section] == 0)
{
WorkflowListViewController *work = [[WorkflowListViewController alloc] init];
work.siteId = self.siteId;
MenuObject *obj = [workflowswithdirectories objectAtIndex:[indexPath row]];
work.menu = obj.next;
work.heading = obj.name;
[self.navigationController pushViewController:work animated:YES];
}
else
{
WorkflowViewController *aWorkFlow = [[WorkflowViewController alloc] init];
MenuObject *obj = [workflownames objectAtIndex:[indexPath row]];
aWorkFlow.heading = obj.name;
aWorkFlow.workId = obj.workflowid;
aWorkFlow.siteId = obj.siteid;
aWorkFlow.item = obj;
[self.navigationController pushViewController:aWorkFlow animated:YES]; //Malloc is on this line
}
}
[tableView deselectRowAtIndexPath:indexPath animated:YES];
EDIT:
Something I forgot to mention is, in certain cases I push another one of this same class onto the navigationcontroller, but it is only when going to the WorkflowViewController and then to the next viewcontroller and then back twice that the exception is thrown

For memory and efficiency's sake, make all UIViewControllers strong properties (with a backing iVar) to guarantee they stay around long enough for anything useful.

Related

My didSelectRowAtIndexPath function causes memory leak

My first post here. Seems I have run into a bit of a memory leak problem.
I have a tab bar with two columns, one for salad and one for sushi. In each tab I also have a tableview that displays the different food choices. When the user presses one of the cells the app takes the user to a more detailview that displays a larger image and some info about the chosen food menu.
But when I run leaks I get a 98,5% leak on the following line.
[self.navigationController pushViewController: detail animated: YES];
if I release detail after this line, the app crashes.
Here is the rest of the function code:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *message = nil;
NSMutableString *image_string = nil;
DetailViewController *detail = [self.storyboard instantiateViewControllerWithIdentifier:#"detailview"];
if(tableView == SushiTable)
{
message = [sushiNames objectAtIndex:indexPath.row];
image_string = [NSMutableString stringWithString:[sushiImages objectAtIndex:indexPath.row]];
}
if(tableView == SaladTable)
{
message = [saladNames objectAtIndex:indexPath.row];
image_string = [NSMutableString stringWithString:[saladImages objectAtIndex:indexPath.row]];
}
[image_string deleteCharactersInRange: [image_string rangeOfString: #"_small"]];
NSMutableString *temp_str = [[message copy] autorelease];
NSString *final = [[[temp_str stringByReplacingOccurrencesOfString:#" " withString:#"_"]
stringByReplacingOccurrencesOfString:#"รค" withString:#"a"]
lowercaseString];
detail.food_name = message;
detail.image_name = image_string;
detail.food_info_key = final;
[tableView deselectRowAtIndexPath:indexPath animated:YES];
[self.navigationController pushViewController: detail animated: YES];
detail = nil;
}
EDIT:
I saw also that in my viewDidLoad function in DetailViewController the following line has a memory leak, don't know if it's maybe related.
food_image.image = [UIImage imageNamed:image_name];
EDIT2:
Also I'm running on the simulator.
Try it.
[self.navigationController pushViewController: detail animated: YES];
[detail release];
detail = nil;
When you push an object.Now it is added into navigation stack array, Now array owner of this object
so you should need release object which you are added in an array.
Declare the detail globally and release it in dealloc:. It may work.

Passing data between two table views

What I am trying to do is .. i want to pass the data between two table views.
In my root view controller I am using an array and then populating it for the RootViewController and in
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
method I am doing this:
if (indexPath.row == 0)
{
self.schedule.title = #"Show1";
NSLog(#"SCHEDULE CONTROLLER TITLE = %#", schedule.title);
NSLog(#"FIRST ROW ");
}
if (indexPath.row == 1) {
self.schedule.title = #"Show2";
NSLog(#"SECOND ROW");
}
if(indexPath.row == 2){
self.schedule.title = #"Show3";
NSLog(#"THIRD ROW");
}
schedule = [[ScheduleViewController alloc] initWithNibName:#"ScheduleViewController" bundle:nil];
[self.navigationController pushViewController:schedule animated:YES];
schedule is another table view so.. what I am doing is I am comparing the titile of schedule to decide the contents of schedule table view, but some how it is not getting the data.
here is ViewDidLoad method of schedule view:
[super viewDidLoad];
if ([self.title isEqualToString:#"Show1"])
{
showSchedule = [[NSArray alloc] initWithObjects:#"SUNDAY",#"MONDAY",#"TUESDAY" , nil];
}
if ([self.title isEqualToString:#"Show2"])
{
showSchedule = [[NSArray alloc] initWithObjects:#"WEDNESDAY",#"THURSDAY",#"FRIDAY" , nil];
}else {
showSchedule = [[NSArray alloc] initWithObjects:#"SATURDAY", nil];
}
[self.tableView reloadData];
The self.title is returning null and therefore it goes into the else loop at the end.
Any ideas what I am doing wrong here.. ?
Thanks for your time in advance
try this.
if ([self.title isEqualToString:#"Show1"])
{
replace this line.
if ([ self.navigationItem.title isEqualToString:#"Show1"])
{
Then try
Adding title before allocing the view...
set your title after alloc the controller
NSString *titleOfTableVC ;
if (indexPath.row == 0)
{
titleOfTableVC = #"Show1";
NSLog(#"SCHEDULE CONTROLLER TITLE = %#", titleOfTableVC );
NSLog(#"FIRST ROW ");
}
if (indexPath.row == 1) {
titleOfTableVC = #"Show2";
NSLog(#"SECOND ROW");
}
if(indexPath.row == 2){
titleOfTableVC = #"Show3";
NSLog(#"THIRD ROW");
}
schedule = [[ScheduleViewController alloc] initWithNibName:#"ScheduleViewController" bundle:nil];
schedule.title = titleOfTableVC ;
[self.navigationController pushViewController:schedule animated:YES];
Hope this will make u understand

SSCollectionView Delegate Problems

I am having a problem with the SSCollectionView control, a subclass of NSTableView from the SSToolkit. For some reason, all delegates except for - (SSCollectionViewItem *)collectionView:(SSCollectionView *)aCollectionView itemForIndexPath:(NSIndexPath *)indexPath are called. Even though this delegate is #required, removing it will cause no exception either. And before you ask, yes the arrays below all have data in them.
I have checked if the data source/delegate becomes nil at any stage, but it doesn't, so I'm baffled.
Here's how I create the view:
- (void)viewDidLoad
{
NSLog(#"ViewDidLoad");
_titles = [[NSMutableArray alloc] init];
_subtitles = [[NSMutableArray alloc] init];
_thumbnails = [[NSMutableArray alloc] init];
_collectionView = [[SSCollectionView alloc] initWithFrame:[UIApplication sharedApplication].keyWindow.frame];
_collectionView.backgroundColor = [UIColor scrollViewTexturedBackgroundColor];
[_collectionView setDelegate:self];
[_collectionView setDataSource:self];
[self.view addSubview:_collectionView];
[_collectionView reloadData];
}
This is called fine and the view appears - but with no data.
This method is never called:
- (SSCollectionViewItem *)collectionView:(SSCollectionView *)aCollectionView itemForIndexPath:(NSIndexPath *)indexPath
{
NSLog(#"Delegate Called");
static NSString *const itemIdentifier = #"itemIdentifier";
SSCollectionViewItem *item = (SSCollectionViewItem *)[aCollectionView dequeueReusableItemWithIdentifier:itemIdentifier];
if (item == nil)
{
item = [[[SSCollectionViewItem alloc] initWithStyle:SSCollectionViewItemStyleImage reuseIdentifier:itemIdentifier] autorelease];
}
item.textLabel.text = [_titles objectAtIndex:indexPath.row];
item.detailTextLabel.text = [_subtitles objectAtIndex:indexPath.row];
item.imageView.image = [_thumbnails objectAtIndex:indexPath.row];
return item;
}
I don't think this is a bug - did I miss something?
This won't get called if there are no items in your collection view. Make sure the following SSCollectionViewDataSource method is implemented and returns a value greater than zero.
- (NSUInteger)collectionView:(SSCollectionView *)aCollectionView numberOfItemsInSection:(NSUInteger)section
Also, make sure you implement the following SSCollectionViewDelegate method as well so your items will be displayed correctly.
- (CGSize)collectionView:(SSCollectionView *)aCollectionView itemSizeForSection:(NSUInteger)section
I would recommend using SSCollectionViewController if it is the only view in your view controller since it will take care of a lot of the glue code for you.
Try to add your - (CGSize)collectionView:(SSCollectionView *)aCollectionView itemSizeForSection:(NSUInteger)section:before viewDidLoad.. don't know why but it works for me this way

some time can't access NSmanagedObject returned form fetchResultController

I have been struggling several days because of some weird overreleased.
My tableView is little bit different type so can't use NSFetchControllerDelegate.
Actually three thumbnail views in each row which can toucable.
So can't use didSelectRowAtIndexPath.
The problem is after execution patch. The first access to NSManagedObject returned from
fetchedResultController objectAt indexPath works ... but second try make access to deallocated object which mean is object is already overreleased.
But the more make me crazy is exact same function in TableViewCellForRowAtIndexPath is work always.
#pragma mark AlbumListViewCellSelectionDelegate ==> my custom delegate method****
- (void)albumContentsTableViewCell:(AlbumLibViewCell *)cell
selectedPhotoAtIndexType:(NSUInteger)index {
//[self fetch];
NSLog(#"select !!!! %i",index);
lastSelectedRow=cell.rowNumber;
//[selectedAssets addObject:[assets objectAtIndex:(lastSelectedRow * imageNoPerRow) + index]];
int selectId =(lastSelectedRow * imageNoPerRow) + index;
if(albumCount >=(selectId+1)){
AlbumTag * album = (AlbumTag *)[fetchedResultsController objectAtIndexPath:[NSIndexPath indexPathForRow:selectId inSection:0]] ;
//scrollView
AutoScrollViewController *detailViewController =[[AutoScrollViewController alloc] init];
detailViewController.hidesBottomBarWhenPushed=YES;
detailViewController.selectedMoments = [album.moments allObjects];==> first work but overrelease every second try
detailViewController.initPhotoNumber = 0;
// Pass the selected object to the new view controller.
[self.navigationController pushViewController:detailViewController animated:YES];
[detailViewController release];
}
same function but every time no problem
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *CellIdentifier = #"AlbumLibViewCell";
AlbumLibViewCell *cell = (AlbumLibViewCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
[[NSBundle mainBundle] loadNibNamed:#"AlbumLibViewCell" owner:self options:nil];
cell = tmpCell;
tmpCell = nil;
}
cell.backgroundColor =[UIColor blackColor];
cell.rowNumber = indexPath.row;
cell.selectionDelegate = self;
// Configure the cell...
NSUInteger firstPhotoInCell = indexPath.row * imageNoPerRow;
NSUInteger lastPhotoInCell = firstPhotoInCell + imageNoPerRow;
if (albumCount <= firstPhotoInCell) {
NSLog(#"We are out of range, asking to start with photo %d but we only have %d", firstPhotoInCell, albumCount);
return nil;
}
NSUInteger currentPhotoIndex = 0;
NSUInteger lastPhotoIndex = MIN(lastPhotoInCell, albumCount);
for (firstPhotoInCell ; firstPhotoInCell + currentPhotoIndex < lastPhotoIndex ; currentPhotoIndex++) {
AlbumTag *albumCell = (AlbumTag *)[fetchedResultsController objectAtIndexPath:[NSIndexPath indexPathForRow:firstPhotoInCell + currentPhotoIndex inSection:0]];
UIImage *thumbnail = albumCell.rpeMomentThumbnail;
NSArray *moments = [albumCell.moments allObjects]; ===> every time works fine
Any idea for this situation might be help
appreciate in advance all.
Seems like objects being passed into detailViewController are being released but not retained. You should turn on NSZombies to debug this. If that doesn't work you can track your allocation history using the ObjectAlloc instrument in Instruments.

UITable view: didselectrowatIndexPath for multiple rows

I have a table view(HomeViewController) consisting of items as:
locations >
Reporting >
Setting >
i am able to do this with the help of "didselectrowatIndexPath" for a single row but when i am trying to do so with multiple rows(if else construct), not getting error but still unable to click on any one (locations,reporting or setting).I have imported .h files of all three above.my code:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if ([[menuList objectAtIndex:indexPath.row] isEqual:#"LOCATIONS"])
{
LocationViewController *locationViewController;
locationViewController = [[LocationViewController alloc] initWithNibName:#"LocationViewController" bundle:nil];
locationViewController.menuList = [menuList objectAtIndex:indexPath.row];
[self.navigationController pushViewController:locationViewController animated:YES];
}
else if([[menuList objectAtIndex:indexPath.row] isEqual:#"REPORTING"])
{
Reporting *reporting;
reporting = [[Reporting alloc] initWithNibName:#"Reporting" bundle:nil];
reporting.menuList = [menuList objectAtIndex:indexPath.row];
[self.navigationController pushViewController:reporting animated:YES];
}
//[locationViewController release];
}
Also want to discuss about release statement
help me!
Thanks
isEqual tests the object's equality to another object. If the strings in your menuList array are all in upper case then this is fine. If they're like they are in your example before the code then you're going to have problems. Also, if they're both NSStrings then you should use isEqualToString rather than isEqual. You can test this by doing something like this:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *arrayValue = [menuList objectAtIndex:indexPath.row];
NSString *myValue = #"LOCATION";
NSLog(#"array value: '%#' my value: '%#'",arrayValue,myValue);
}
The release is not valid because the object is "out of scope".
An objects scope is the current "visible" code base for that variable. Here are some examples:
- (void)aRandomFunction {
/* here is a variable/object. Its scope is the whole function because it has been
declared directly in the function. All constructs have access to it (within the function) */
NSString *myString = #"My String";
if(YES){
NSLog(#"%#", myString); // myString is visible here because its in scope.
}
}
- (void)anotherRandomFunction {
if(YES){
/* here, because we've declared the variable within the if statement
it's no longer a direct object of the function. Instead its a direct
child of the if statement and is therefore only "visible" within that
if statement */
NSString *myString = #"My String";
NSLog(#"%#", myString); // myString is visible here because its in scope.
}
NSLog(#"%#", myString); // but NOT available here because it is out of scope
}
So in essence, a variable's scope is its direct parent construct and all its parent's children constructs.
So there is two ways to do your example. My favourite is this way:
- (void)aFunctionToPushAViewController {
UIViewController *nextPage = NULL;
if(YES){
nextPage = [[CustomViewController alloc] initWithNibName:nil bundle:nil];
}
else {
nextPage = [[ADifferentViewController alloc] initWithNibName:nil bundle:nil];
}
[self.navigationController pushViewController:nextPage animated:YES];
[nextPage release];
}
or... you can just release it in the if statement...
- (void)aFunctionToPushAViewController {
if(YES){
CustomViewController *nextPage = [[CustomViewController alloc] initWithNibName:nil bundle:nil];
[self.navigationController pushViewController:nextPage animated:YES];
[nextPage release];
}
else {
ADifferentViewController *nextPage = [[ADifferentViewController alloc] initWithNibName:nil bundle:nil];
[self.navigationController pushViewController:nextPage animated:YES];
[nextPage release];
}
}