UITable view: didselectrowatIndexPath for multiple rows - iphone

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

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.

NSZombie in didSelectRowAtIndexPath

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.

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

How to push view depending on the row selection?

/*****UPDATED** ***/r.com/YH3cm.png
I am trying to figure out in the above image, how will we know if the user has selected Date or Track.
/UPDATED/
The data I am receving is through a select query and I create an array to store the list. It is dynamic and not necessary limited to two fields, it can have 10 fields also. How will I know which row is selected and how will I push the data on to the next view.
Like in didSelectRowAtIndexPath, how should I push the date or track field on the next view?
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if (dvController == nil)
dvController = [[DetailViewController alloc] initWithNibName:#"DetailView" bundle:nil];
Teat *obj = [appDelegate.coffeeArray objectAtIndex:indexPath.row];
dvController.obj = obj;
// Pass the selected object to the new view controller.
[self.navigationController pushViewController:dvController animated:YES];
}
It's still not very clear what you're trying to do. If you want to push a certain view controller depending on what the content of the cell is, but there is no definite arrangement of the rows, I would use the row index to access the array that is the source of your data. Some very loose code:
WhateverObject* selectedObject= (WhateverObject*)[tableDataSourceArray objectAtIndex:indexPath.row];
if( [selectedObject hasAnAttributeYouCareAbout] )
{
MyViewController* theCorrectController= whicheverViewControllerYouWant;
theCorrectController.anAttribute= aValue;
[self.navigationController pushViewController:theCorrectController animated:YES];
}
And here's how you can define your UIViewController subclass MyViewController with specific attributes. In the .h file:
#interface MyViewController : UIViewController {
int anAttribute;
}
#property int anAttribute
#end
In the .m file:
#implementation MyViewController
#synthesize anAttribute;
#end
You can have as many attributes as you want of whatever type, and then you can set them with aViewController.anAttribute as above.
Create objects - dateInfoViewController and trackInfoViewController and then...
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSInteger row = [indexPath row];
if (row==0)
{
if (self.dateInfoViewController == nil)
{
DateInfoViewController *temp = [[DateInfoViewController alloc] init];
self.dateInfoViewController = temp;
[temp release];
}
else {
dateInfoViewController.title= [ NSString stringWithFormat:#"%#", [sessionInfoDetailsArray objectAtIndex:row]];
YourAppDelegate *delegate = [[UIApplication sharedApplication]delegate];
[delegate.sessionNavigationController pushViewController:dateInfoViewController animated:YES];
}
}
if (row==1)
{
if (self.vetInfoViewController == nil)
{
TrackInfoViewController *temp = [[TrackInfoViewController alloc] init];
self.trackInfoViewController = temp;
[temp release];
}
else {
trackInfoViewController.title= [ NSString stringWithFormat:#"%#", [sessionInfoDetailsArray objectAtIndex:row]];
YourAppDelegate *delegate = [[UIApplication sharedApplication]delegate];
[delegate.sessionNavigationController pushViewController:trackInfoViewController animated:YES];
}
}
I fear it's not perfectly clear what do you want to do... if you need to push a different view depending on the selected row you may simply do something like
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.row == 0)
//push view 1
else
//push view 2
}
UPDATE: calling indexPath.row you get the index of the selected row. I guess is up to you to decide what to do depending on what row is selected. To pass this information to the next view you may simply think of a #property field to set, a method to call or a custom init method for the view controller you are pushing. What is the problem with the code you posted?

Problems sending NSString variables to a ViewController before it is pushed

I am having problems sending along 2 NSString variables to a view controller right before it is pushed.
here is some relevent code for pushing the controller:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
CommentsViewController *c = [[CommentsViewController alloc] initWithNibName:#"CommentsView" bundle:nil];
c.subreddit = subreddit;
c.redditId = [[[list objectAtIndex:indexPath.row] objectForKey:#"data"] objectForKey:#"id"];
c.title = [[[list objectAtIndex:indexPath.row] objectForKey:#"data"] objectForKey:#"title"];
[self.navigationController pushViewController:c animated:YES];
[c release];
NSLog(#"subreddit: %#", subreddit);
NSLog(#"redditId: %#", [[[list objectAtIndex:indexPath.row] objectForKey:#"data"] objectForKey:#"id"]);
}
note that printing out the variables via NSLog works as expected.
also, the c.title assignment seems to work fine, as i can see the title text on the pushed controller.
here(not just here, anywhere) is where i am finding (null) when printing the corresponding variables which i have assigned:
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(#"subreddit: %#", subreddit);
NSLog(#"redditId: %#", redditId);
}
2010-12-30 20:06:17.108 RedditReader[1073:307] subreddit: (null)
2010-12-30 20:06:17.131 RedditReader[1073:307] redditId: (null)
subreddit has property set as: #property (nonatomic, retain) NSString *subreddit;
Why can't i seem to assign these values correctly so i can use them in the pushed view controller?
How can i assign these values so i can use them in the pushed view controller?
It seems like your viewDidLoad gets called before the variables are set (I don't use nib files so I can't say for sure...). You could make an init method that receives those variables, like this:
- (id)initWithTitle:(NSString *)aTitle reddit:(NSString *)aReddit ... {
self.title = aTitle;
// ...
if (self = [super initWithNibName:#"CommentsView" bundle:nil]) {
// ...
}
return self;
}
Hope this helps!
Override viewWillAppear and you should see your populated variables, viewDidLod is called when uniting from the nib