Return NSDictionary data from popup tableview - iphone

I have a popup tableview (ViewController2) appearing when I click a button on ViewController1. Then when I select a row in the table, I want those values to be sent back to ViewController1. I have a NSDictionary set up. It works fine in a regular navigation controller, but trying to do it with dismissModalViewControllerAnimated, so the tableview drops back down, and the data is appearing in the first view.
This is similar to this question here I think: http://www.iphonedevsdk.com/forum/iphone-sdk-development/39995-return-data-dismissmodalviewcontrolleranimated.html
Here is my code:
ViewController1.h:
#protocol ViewController1Delegate;
#interface ViewController1 : UIViewController <ViewController2Delegate> {
id <ViewController1Delegate> delegate;
}
#property (nonatomic, assign) id <ViewController1Delegate> delegate;
#end
#protocol ViewController1Delegate
- (void)viewController1DidFinish:(ViewController1 *)controller;
#end
ViewController1.m:
-(void)buttonGoToViewController2 {
ViewController2 *controller = [[ViewController2 alloc] initWithNibName:#"ViewController2" bundle:nil];
// this controller.delegate = self causes it to crash if i have it uncommented for some reason...
// controller.delegate = self;
controller.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
[self presentModalViewController:controller animated:YES];
[controller release];
}
ViewController2.m:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if(searching) {
// Navigation logic may go here. Create and push another view controller.
NSDictionary *selectedCountry = [self.copyListOfItems objectAtIndex:indexPath.row];
ViewController1 *dvController = [[ViewController1 alloc] initWithNibName:#"ViewController1" bundle:nil andDictionary: selectedCountry];
NSLog(#"selected hit this %#",selectedCountry);
// Pass the selected object to the new view controller.
[self.navigationController pushViewController:dvController animated:YES];
[dvController release];
[self dismissModalViewControllerAnimated:YES];
}
else {
// Navigation logic may go here. Create and push another view controller.
NSDictionary *dictionary = [self.listOfItems objectAtIndex:indexPath.row];
ViewController1 *dvController = [[ViewController1 alloc] initWithNibName:#"ViewController1" bundle:nil andDictionary: dictionary];
NSLog(#"normal hit this %#",dictionary);
// Pass the selected object to the new view controller.
[self.navigationController pushViewController:dvController animated:YES];
[dvController release];
}
}

In your ViewController2 code you are creating a new ViewController1 object and giving it your NSDictionary. When you dismiss ViewController2 you go back to the original ViewController1, which never went anywhere and was never sent the NSDictionary. You need to provide ViewController2 with access to the ViewController1 object that presented it (I suggest doing it via a delegate pattern) in order to set the NSDictionary there.

Related

Passing data from one view controller to other view controller through xib file

I want to make one app and it include form submition . In this i create one new project by single view application. In this firstViewController I have put button and by pressing it , it redirect to secondViewController.
In this i have a form. and want to take data from user and by submit button i want to redirect this to thirdViewController and want to print the form data on thirdViewController.
In firstViewController.m file i have written
-(IBAction)nextVCButton:(id)sender
{
SecondViewController *tempView = [[SecondViewController alloc] initWithNibName:#"SecondViewController" bundle:nil];
NSLog(#"name : %#",self.nameTextField.text);
tempView.fullName = self.nameTextField.text;
[tempView setFullName:self.fullName];
[self.view addSubview:tempView.view];
}
In SecondViewController.m file
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
NSLog(#"received info %#", [self.fullName description]);
self.nameLabel.text = [self.fullName description];
}
In log i am getting (name :) value but in secondViewController received info is null.
I am doing this all by using xib file. No use of Storyboard.
Please help me to get this form data to secondViewController.
Thanks.
Sorry , I couldn't get why you have done these two line code :
tempView.fullName = self.nameTextField.text;
[tempView setFullName:self.fullName];
Instead ,
Make a property of NSString in Second View Controller's .h file
#property (nonatomic,retain) NSString *strFullName;
and synthesize in .m file.
#synthesize strFullName;
Now ,
-(IBAction)nextVCButton:(id)sender
{
SecondViewController *tempView = [[SecondViewController alloc] initWithNibName:#"SecondViewController" bundle:nil];
NSLog(#"name : %#",self.nameTextField.text);
tempView.strFullName = self.nameTextField.text;
[self.view addSubview:tempView.view];
}
I think you need to use Navigation controller if you want to navigate from one view controller to another view controller. well here you need to do property- synthesize the iVar "fullName" in ThirdViewController. and retain the value in SecondViewController .
1. ThirdViewController.h
#property(nonatomic, retain) NSString *fullName;
2. ThirdViewController.m
#synthisize fullName;
dealloc {
[fullName release];
}
3. SecondViewController.m
-(IBAction)nextVCButton:(id)sender
{
SecondViewController *tempView = [[SecondViewController alloc] initWithNibName:#"SecondViewController" bundle:nil];
NSLog(#"name : %#",self.nameTextField.text);
tempView.fullName = self.nameTextField.text;
[tempView setFullName:self.fullName];
[self.view addSubview:tempView.view];
}
try presentViewController method instead of addSubview....
-(IBAction)nextVCButton:(id)sender
{
SecondViewController *tempView = [[SecondViewController alloc] initWithNibName:#"SecondViewController" bundle:nil];
NSLog(#"name : %#",self.nameTextField.text);
tempView.strFullName = self.nameTextField.text;
[self.view addSubview:tempView.view];
[self presentViewController:tempView animated:YES completion:nil];
}

PushViewController does not work when called from App Delegate

I have a tab-bar based app. When the app becomes active, I want it to go to the second tab bar (SecondViewController) and then, open DetailViewController.
Here's how I'm doing it:
AppDelegate.m
- (void)applicationDidBecomeActive:(UIApplication *)application {
self.tabBarController.selectedViewController = [self.tabBarController.viewControllers objectAtIndex:1];
SecondViewController *secondView = [[SecondViewController alloc] init];
[secondView openDetailView];
[secondView release];
}
SecondViewController.m
-(void)openDetailView{
NSLog(#"open detail view");
DetailViewController *detailViewController = [[DetailViewController alloc] initWithNibName:#"DetailViewController" bundle:nil];
[[self navigationController] pushViewController:detailViewController animated:YES];
}
openDetailView() does run (as I see the nslog working), but the DetailView does not get pushed? I know the code works because I have identical code in an IBAction which DOES push the detailView. The problem has something to do with it being called from the AppDelegate (or switching tabs).
So why doesn't the view get pushed when I call it from the App Delegate? Any help is greatly appreciated.
You push detailViewController to the Navigation-Stack of secondView, but secondView is in nowhere.
Try this...
SecondViewController *secondView ...
[self.tabBarController pushViewController:secondView animated:YES]; <==
[secondView openDetailView];

popToRootViewController crashes when called by UITabBarControllerDelegate

I have a UITabBarController with 4 UINavigationControllers. I have implemented the didSelectViewController Delegate Method as follows:
-(void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController {
if ([viewController isKindOfClass:[UINavigationController class]]) {
[(UINavigationController *)viewController popToRootViewControllerAnimated:NO];
}
}
It crashes when a NavigationController is at a 2nd Level after didSelectRowAtIndexPath pushes a new viewController onto the stack.
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
// Navigation logic may go here. Create and push another view controller.
RootViewController *detailViewController = [[RootViewController alloc] initWithNibName:#"RootViewController" bundle:nil];
// ...
detailViewController.title = [self.temp objectAtIndex:indexPath.row];
detailViewController.sort = self.title;
// Pass the selected object to the new view controller.
[self.navigationController pushViewController:detailViewController animated:YES];
[detailViewController release];
}
Of course the debugger with NSZombies enabled doesn't give any feedback.
However, if I add retain to detailViewController alloc;
RootViewController *detailViewController = [[[RootViewController alloc] initWithNibName:#"RootViewController" bundle:nil] retain];
It works, but leaks memory.
Any ideas what is wrong, how to fix, what is happening?
I have the similar scenario and i came up with following solution.
In my application i have login screen at launch and then I have UITabbarController with 4 UINavigationControllers.
I have created property of UINavigationController in AppDelegate.h file.
#property (strong, nonatomic) UINavigationController *navigationController;
Then
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions (NSDictionary *)launchOptions
{
//Override point for customization after application launch.
LoginViewController *loginViewController = [[LoginViewController alloc] initWithNibName:#"LoginViewController" bundle:nil];
self.navigationController = [[UINavigationController alloc] initWithRootViewController:loginViewController];
self.window.rootViewController = self.navigationController;
[self.window makeKeyAndVisible];
return YES;
}
Now when you need to pop to RootViewController then use following code
#import "AppDelegate.h"
[((AppDelegate *)[[UIApplication sharedApplication] delegate]).navigationController popToRootViewControllerAnimated:YES];
Hope this solves your problem.

Pushing UIViewController onto a UINavigationController

The other day I asked about using a UINavigationController as a child of a UIViewController. I got that working via the answer. Now what I'm trying to do is push a controller onto the nav stack. When a table cell is touched, I do the following:
- (void) showSetup {
NSLog(#"Showing Setup");
SetupViewController *controller = [[SetupViewController alloc]initWithNibName:#"SetupViewController" bundle:nil];
self.setupViewController = controller;
self.setupViewController.title = #"Setup";
[self.navigationController pushViewController:self.setupViewController animated:YES];
[controller release];
}
I can see the log statement in my console, but the view never changes. Am I missing something?
Hmmm, well it's a bit tricky without knowing the details of your implementation -- I assumed that you implemented your navigation controller as in the linked article. Also although you give no details it sounds like you've added a table view controller somewhere along the line, so I made the UIViewController conform to the UITableView protocols to handle everything in one place:
#interface SOViewController : UIViewController<UITableViewDelegate,UITableViewDataSource > {
UINavigationController* navController;
}
- (IBAction) pushMe:(id)sender;
#end
I dropped a button on the SOViewController's view in IB and wired the pushMe: action to it. I also created another UIViewController-based class called JunkController and dropped a "Junk" label on it's view in IB -- that's all I did in IB. In the SOViewController's viewDidLoad:
navController = [[[UINavigationController alloc] init] retain];
navController.navigationBar.barStyle = UIBarStyleBlackOpaque;
navController.toolbarHidden = YES;
UITableViewController* tvController = [[UITableViewController alloc] init];
UITableView* tv = [[UITableView alloc] init];
tvController.tableView = tv;
tv.delegate = self;
tv.dataSource = self;
[navController setViewControllers:[NSArray arrayWithObject:tvController]];
In the pushMe: action implementation:
[self presentModalViewController:navController animated:YES];
Implemented the tableView delegate and datasource methods; for selection:
- (void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSLog(#"row selected");
JunkController* junk = [[JunkController alloc] initWithNibName:#"junkcontroller" bundle:nil];
[navController pushViewController:junk animated:YES];
[junk release];
}
This should yield an app that surfaces a screen with a "Push me" button. When that button is pressed you should get an animated modal navigation-based table view -- mine had one row in it that contained a label "select me". Touching this row should animate the junk controller into view.
There is no need to make setupViewController a declared property in this view controller. Also, I could be mistaken but I thought "controller" was a reserved name in Cocoa, I'd change that name. So make sure you have registered with the UITableViewDelegate and use - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath to hook into and push your new view controller as follows:
SetupViewController *detailViewController = [[SetupViewController alloc] initWithNibName:#"SetupViewController" bundle:nil];
detailViewController.title = #"Setup";
[self.navigationController pushViewController:detailViewController animated:YES];
[detailViewController release];
Goodluck!

UISplitViewController - Dealing with memory warnings

I'm using a UISplitViewController where when the Master VC is loaded (UITableViewController) and a table cell is pressed, it creates the Detail VC (UIViewController with two UIWebViews):
#implementation MasterVC
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
UIViewController *detailViewController = nil;
DetailVC *newDetailViewController = [[DetailVC alloc] initWithNibName:#"DetailVC" bundle:nil];
detailViewController = newDetailViewController;
// Update the split view controller's view controllers array.
NSArray *viewControllers = [[NSArray alloc] initWithObjects:self.navigationController, detailViewController, nil];
splitViewController.viewControllers = viewControllers;
[viewControllers release];
[detailViewController release];
}
If I simulate a memory warning, the DetailVC is released (didReceiveMemoryWarning, viewDidUnload, dealloc are called) but I get a "-[UIView _invalidateSubviewCache]: message sent to deallocated instance" error at the line in MasterVC where I release the viewControllers, which make sense since since it tries to load the detailViewController (DetailVC) which was released due to the memory warning. Why it has to release the detail vc since it's view is the one being displayed, I don't fully understand.
Now, if instead of releasing the detailViewController inside didSelectRowAtIndexPath, I release it inside viewWillDisappear, everything works fine:
#implementation MasterVC
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
UIViewController *detailViewController = nil;
DetailVC *newDetailViewController = [[DetailVC alloc] initWithNibName:#"DetailVC" bundle:nil];
detailViewController = newDetailViewController;
// Update the split view controller's view controllers array.
NSArray *viewControllers = [[NSArray alloc] initWithObjects:self.navigationController, detailViewController, nil];
splitViewController.viewControllers = viewControllers;
[viewControllers release];
// Released in viewWillDissapear
//[detailViewController release];
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
MyAppDelegate *delegate = [[UIApplication sharedApplication] delegate];
// Retrieve the detail vc and release it-[UIView _invalidateSubviewCache]: message sent to deallocated instance
[[delegate.splitViewController.viewControllers objectAtIndex:1] release];
}
For me, it makes (some) sense to release the detail view controller when the master view controller will dissapear, but still, it kind of seems like a hack (plus the Static Analyzer complains of not releasing the detail vc in the 'right' place). Any other better ways to solve this?