I am calling a login view modally in the view did load method in the root view controller, but when I dissmiss the modal view controller it just reappears! any suggestions?
hears the code:
** .h **
//
// FirstViewController.h
// Voyager
//
// Created by Peter Unger on 9/1/13.
// Copyright (c) 2013 Penumbra Software. All rights reserved.
//
#import <UIKit/UIKit.h>
#import <Parse/Parse.h>
#interface FirstViewController : UIViewController
#end
#interface DefaultSettingsViewController :
UIViewController <PFLogInViewControllerDelegate, PFSignUpViewControllerDelegate>
#end
** .m **
//
// FirstViewController.m
// Voyager
//
// Created by Peter Unger on 9/1/13.
// Copyright (c) 2013 Penumbra Software. All rights reserved.
//
#import "FirstViewController.h"
#import <Parse/Parse.h>
#interface FirstViewController ()
#end
#implementation FirstViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
PFLogInViewController *login = [[PFLogInViewController alloc] init];
login.fields = PFLogInFieldsUsernameAndPassword | PFLogInFieldsLogInButton | PFLogInFieldsSignUpButton;
login.delegate = (id)self;
login.signUpController.delegate = (id)self;
[self presentViewController:login animated:YES completion:nil];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)logInViewController:(PFLogInViewController *)logInController didLogInUser:(PFUser *)user {
[self dismissViewControllerAnimated:YES completion:nil];
}
- (void)signUpViewController:(PFSignUpViewController *)signUpController didSignUpUser:(PFUser *)user {
[self dismissViewControllerAnimated:YES completion:nil];
}
#end
As #Bergasms already said, you have a loop. the viewDidAppear method is called everytime your viewController appears in the screen. So, when you resign the presented viewController, the first view controller was supposed to appear, calling then the viewDidAppear, which will present again the PFLogInViewController, creating a loop.
If you move the code to the viewDidLoad method, your modal will be called just once, as this method is called only when the viewController is allocated.
And if you want the user to do not see the first viewController, you may want to set the animation in the presentViewController:animated:completion: to NO.
Edit:
One person said in another question that you might get an error if you call another view controller inside viewDidLoad (although I have done this once, haven't checked the behavior of the error yet). If that's your case and you get an error, you would have to let the code in viewDidAppear.
And if somehow you still want use viewDidAppear, you can simply create a BOOL property that controls if the PFLogInViewController was already called or not. It will be something like this
#property(nonatomic, assign) BOOL isLogged;
And
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
if (!self.isLogged)
{
self.isLogged = YES;
PFLogInViewController *login = [[PFLogInViewController alloc] init];
login.fields = PFLogInFieldsUsernameAndPassword | PFLogInFieldsLogInButton | PFLogInFieldsSignUpButton;
login.delegate = (id)self;
login.signUpController.delegate = (id)self;
[self presentViewController:login animated:YES completion:nil];
}
}
In this way, your PFLogInViewController will be called once.
You have a loop there. When the modal controller is dismissed, the viewDidAppear method will be called on first view controller, which will launch the modal view again. You should put comments or break points at the launch code to help debug things like this.
#interface FirstViewController (){
BOOL has_shown_login_modal;
}
#end
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
has_shown_login_modal = NO;
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
if(!has_shown_login_modal){
PFLogInViewController *login = [[PFLogInViewController alloc] init];
login.fields = PFLogInFieldsUsernameAndPassword | PFLogInFieldsLogInButton | PFLogInFieldsSignUpButton;
login.delegate = (id)self;
login.signUpController.delegate = (id)self;
[self presentViewController:login animated:YES completion:nil];
has_shown_login_modal = YES;
}
}
Related
I have gone through most of the previous related posts, but although I have followed them correctly (as far as i understood), I simply am not able to trigger the delegate method for below code.
Objective: ModalView generates a string *SQL_String. Press DONE to dismiss the ModalView and trigger the delegate method in the parentview to get that *SQL_String.
SearchModalViewController.h
#protocol SearchControllerDelegate
- (void)didDismissModalView:(NSString *)SQL_String;
#end
#interface SearchModalViewController : UIViewController
#property (nonatomic, assign) id <SearchControllerDelegate> searchDelegate;
- (IBAction)handleDone:(id)sender;
SearchModalViewController.m
#interface SearchModalViewController ()
#end
#implementation SearchModalViewController
#synthesize searchDelegate;
- (IBAction)handleDone:(id)sender {
[self dismissView:sender];
}
- (void)dismissView:(id)sender {
[searchDelegate didDismissModalView:#"Test"];
[self dismissViewControllerAnimated:YES completion:nil];
}
DetailViewController.m (My parent View Controller)
#interface DetailViewController () <SearchControllerDelegate>
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
SearchModalViewController *searchModal = [[SearchModalViewController alloc] init];
searchModal.searchDelegate = self;
}
PROBLEM:
Below delegate method is not getting triggered.
- (void)didDismissModalView:(NSString *)SQL_String {
[self dismissViewControllerAnimated:YES completion:nil];
NSLog(#"The string = %#", SQL_String);
}
Any idea where I am doing wrong?
EDIT: Thank you guys. With your fast suggestions, I am able to close it down by adding below code instead of my previous IB connection.
- (IBAction)showSearchModal:(id)sender {
SearchModalViewController *searchModal = [self.storyboard instantiateViewControllerWithIdentifier:#"search"];
searchModal.searchDelegate = self;
searchModal.modalPresentationStyle = UIModalPresentationFormSheet;
searchModal.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[self presentViewController:searchModal animated:YES completion:nil];
}
Here it goes
Change DetailViewController.m
- (IBAction)pushToSearch:(id)sender{
SearchModalViewController *searchModal = [self.storyboard instantiateViewControllerWithIdentifier:#"search"];
searchModal.searchDelegate = self;
[self presentViewController:searchModal animated:YES completion:nil];
}
And it will work.
Firstly, make sure your dismissView: of the SearchModalViewController is getting triggered.
Secondly, make sure your searchDelegate in the dismissView: method is not nil.
You need to set the delegate when you present the SearchModalViewController. The reason why your code doesn't currently work, is because the modal view controller's delegate is nil.
Update:
You set the delegate in prepareForSegue:sender:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)__unused sender
{
if ([[segue identifier] isEqualToString:#"modalSearch"])
{
SearchModalViewController *controller = (SearchModalViewController *)[segue destinationViewController];
controller.delegate = self;
}
}
im a beginner and trying to figure out how to work with nib properly.
I have a HomeViewController.h:
#import <UIKit/UIKit.h>
#import "StackTableViewController.h"
#interface HomeViewController : UIViewController
#property (strong, nonatomic) StackTableViewController *stackViewController;
- (IBAction)goToStack:(id)sender;
#end
HomeViewController.m:
#import "HomeViewController.h"
#interface HomeViewController ()
#end
#implementation HomeViewController
- (id)init {
self = [super initWithNibName:#"HomeViewController" bundle:nil];
if (self) {
//
_stackViewController = [[StackTableViewController alloc]init];
}
return self;
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)goToStack:(id)sender {
//[self.navigationController showViewController:_stackViewController sender:self];
[self presentViewController:_stackViewController animated:YES completion:nil];
}
As you can see I'm modelling from the HomeViewController to StackTableViewController...
Now it works ok, but I want that StackTableViewController will be embedded in NavigationController...that I can put a cancel button in the top.
This is my StackTableViewController.m:
#import "StackTableViewController.h"
#interface StackTableViewController ()
#property (strong, nonatomic) UINavigationController *navBar;
#end
#implementation StackTableViewController
- (void)viewDidLoad {
[super viewDidLoad];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
#warning Potentially incomplete method implementation.
// Return the number of sections.
return 0;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
#warning Incomplete method implementation.
// Return the number of rows in the section.
return 0;
}
What should I add to the viewDidLoad method that will embed the navBar in the tableview?
tnx
There is not need to declare StackTableViewController as a property of HomeViewController, just modify goToStack like so:
- (IBAction)goToStack:(id)sender {
StackTableViewController *stackViewController = [[StackTableViewController alloc] init]; // shouldnt this get loaded from a NIB though???
[self presentViewController:stackViewController animated:YES completion:nil];
}
About youer issue with UINavigationController, depending on your setup the UINavigationController is the base for a certain navigation stack within your app, so, if you're just building a simple app without a tab bar or another more complex interface, your UINavigationController might be the rootViewController of your application's main UIWindow (a property of your AppDelegate).
So, what you will have to do to get this setup to work is in application:didFinishLaunchinWithOptions of your AppDelegate, set the application's root window:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
HomeViewController *homeViewController = [[HomeViewController alloc] initWithNibName:#"HomeViewController" bundle:nil]; // I assume you have a NIB file called HomeViewController
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:homeViewController];
self.window.rootViewController = navigationController;
return YES;
}
This will have the effect that the HomeViewController that you will see on application startup, is embedded within an instance of UINavigationController, which again is the rootViewController of your whole application.
Then again, you can modify goToStack to use this instance of UINavigationController instead of showing stackViewController modally:
- (IBAction)goToStack:(id)sender {
StackTableViewController *stackViewController = [[StackTableViewController alloc] init]; // shouldnt this get loaded from a NIB though???
[self.navigationController pushViewController:stackViewController animated:YES];
}
You can use self.navigationController here because homeViewController is embedded in a UINavigaitonController, so iOS will set this property for you.
Hope that helps! :)
Update:
If you don't want to have your HomeViewController embedded within the UINavigationController, just modify goToStack like so:
- (IBAction)goToStack:(id)sender {
StackTableViewController *stackViewController = [[StackTableViewController alloc] init]; // shouldnt this get loaded from a NIB though???
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:stackViewController];
[self presentViewController:navigationController animated:YES completion:nil];
}
i have to view controllers .. and i want to pass data from the first to the second view i have this code
for the ViewController.h
#import <UIKit/UIKit.h>
#import "SecondView.h"
#interface ViewController : UIViewController{
SecondView *secondviewData;
IBOutlet UITextField *textfield;
}
#property (nonatomic,retain) SecondView *secondviewData;
-(IBAction)passdata:(id)sender;
#end
for the viewController.m
#import "ViewController.h"
#import "SecondView.h"
#interface ViewController ()
#end
#implementation ViewController
#synthesize secondviewData;
-(IBAction)passdata:(id)sender{
SecondView *second= [[SecondView alloc] initWithNibName:nil bundle:nil];
self.secondviewData=second;
secondviewData.passedValue=textfield.text;
[self presentModalViewController:second animated:YES];
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
for the second view controller which is SecondView.h
#import <UIKit/UIKit.h>
#interface SecondView : UIViewController{
IBOutlet UILabel *label;
NSString *passedValue;
}
#property (nonatomic,retain) NSString *passedValue;
-(IBAction)back:(id)sender;
#end
for the SecondView.m
#import "SecondView.h"
#import "ViewController.h"
#interface SecondView ()
#end
#implementation SecondView
#synthesize passedValue;
-(IBAction)back:(id)sender{
ViewController *vc= [[ViewController alloc] initWithNibName:nil bundle:nil];
[self presentModalViewController:vc animated:YES];
}
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
label.text=passedValue;
[super viewDidLoad];
// Do any additional setup after loading the view.
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
/*
#pragma mark - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}
*/
#end
the error I'm having is presentModalViewController deprecated iOS 6 in these 2 lines
[self presentModalViewController:vc animated:YES];
[self presentModalViewController:vc animated:YES];
and when i run it and click on the button it will stop working and displays a blank black page
You can save data in AppDelegate to access it across view controllers in your application. All you have to do is create a shared instance of AppDelegate
AppDelegate *appDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
If you are building for >= iOS 5 then you should be using presentViewController:animated:completion: instead of presentModalViewController:animated:.
Also, the idea of 'back' doesn't usually mean pushing something new. So, this code:
- (IBAction)back:(id)sender {
ViewController *vc= [[ViewController alloc] initWithNibName:nil bundle:nil];
[self presentModalViewController:vc animated:YES];
}
should change to:
- (IBAction)back:(id)sender {
[self dismissViewControllerAnimated:YES completion:nil];
}
Now, you should look at using a delegate pattern to pass the data back to the originating view controller. And preferably that delegate implementation would include telling the delegate that the second controller is finished and the delegate triggers the dismiss.
See Passing Data between View Controllers
I want to transition to a view I made in the main.storyboard, when they enter the password correctly.
How do I do this?
I need it to pull up the view I already created. I want a transition in the code block -(void) unlock.
Code
//
// ViewController.m
// Login
//
// Created by Ben Rosen on 5/24/14.
// Copyright (c) 2014 Ben Rosen. All rights reserved.
//
#import "ViewController.h"
#import "UnlockedScreen.h"
#interface ViewController ()
#end
#implementation ViewController
-(IBAction)login:(id)sender
{
NSString *correctUser = #"money";
NSString *correctPassword = #"ilovemoney";
if ((usernameTextField.text == correctUser)==YES && (passwordTextField.text = correctPassword)==YES)
{
[self unlock];
}
}
-(void) unlock
{
// here should be the transition
}
- (void)viewDidLoad
{
[super viewDidLoad];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(UIStatusBarStyle)preferredStatusBarStyle
{
return UIStatusBarStyleLightContent;
}
#end
In you storyboard, go on your first view controller, press CTRL click on the viewController and release the mouse (and CTRL) on the destination view controller.
Now choose type of segue (push if you are in a navigationController otherwise modal) and choose an identifier on the inspector for this trigger.
In your code:
-(IBAction)login:(id)sender
{
NSString *correctUser = #"money";
NSString *correctPassword = #"ilovemoney";
if ([usernameTextField.text isEqualToString:correctUser] && [passwordTextField.text isEqualToString:correctPassword])
{
[self performSegueWithIdentifier:#"name" sender:sender];
}
}
As you see i changed your if statement..your compare was wrong.
[self unlock];
remove it and write this method
[self performSegueWithIdentifier:#"profileSegue" sender:self] ;
in the storyboard name to identifier(profileSegue) on the inspector
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"profileSegue"]) {
ProfileViewController *profileViewController = segue.destinationViewController;
profileViewController.isFromDealView = YES;
profileViewController.hidesBottomBarWhenPushed = YES;
}
Instantiate your viewController with the identifier you have provided for your viewController.
-(void) unlock
{
// here should be the transition
UIViewController *vc = [[UIStoryboard storyboardWithName:#"storyboardname" bundle:nil] instantiateViewControllerWithIdentifier:#"viewControllersID"];
[self presentViewController:vc animated:YES completion:nil];
}
I'm fairly new to Objective-C, programming. The one thing, I'm currently putting up with is passing a value from the first ViewController to the next one.
I've read this entry here and it didn't help me. Which is funny, since his answer has nearly 500 votes, so I must be the problem. What I did was the following.
I opened my PreviewViewController.m and added the following line #import "MainViewController.h" since I wanted to pass a value from the PreviewViewController to the `MainViewController. Then, when I switch the layouts ( which successfully works ) I want to pass a value.
MainViewController *mainViewController = [[MainViewController alloc] initWithNibName:#"MainViewController" bundle:nil];
mainViewController.userId = #"539897197";
As you can see, I want to pass the userId. For that, I also created a property in the MainViewController.h
#property ( nonatomic, strong ) NSString *userId;
Now, In my MainViewController.m I want to access the userId. But when I log it, the console tells me it is null. However, when I set the variable right before the NSLog it works, so it seems like the passing is the problem.
Additionally in the MainViewController.m I have the following line
#synthesize userId = _userId;
but even when I removed that line and changed the NSLog to NSLog(#"%#",self.userId); the same problem occurred.
How can I successfully pass the variables? Which step am I doing wrong?
EDIT
This is how I switch the layouts
UIViewController *viewController = [[MainViewController alloc]init];
MainViewController *mainViewController = [[MainViewController alloc] initWithNibName:#"MainViewController" bundle:nil];
mainViewController.userId = #"539897197";
[self presentViewController:viewController animated:YES completion:NULL];
Why not create a custom initializer and pass it in that way? Something like
- (id)initWithUserId:(NSString *)aUserId {
self = [super initWithNibName:#"MainViewController" bundle:nil];
if (self) {
self.userId = aUserId
}
return self;
}
Then you can just do:
MainViewController *mvc = [[MainViewController alloc] initWithUserId:#"1234"]
[self presentViewController:mvc animated:YES completion:nil];
If you are using storyboard then you should use prepareForSegue: method to pass data between view controllers. First Create the segue from your PreviewViewController to MainViewController, just control drag from your view controller to next viewcontroller to create segue. Use UINavigationController if you are using push segue. Use this method to segue and pass data
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if([segue.identifier isEqualToString:#"yourSegueIndentifier"]){
MainViewController *mvc = (MainViewController *) segue.destinationViewController;
mvc.userId = #"539897197";;
}
}
UIViewController *viewController = [[MainViewController alloc]init];
MainViewController *mainViewController = [[MainViewController alloc] initWithNibName:#"MainViewController" bundle:nil];
mainViewController.userId = #"539897197";
[self presentViewController:mainViewController animated:YES completion:NULL];
use mainViewController rather than viewController when presenting the view controller
Here we have two ways for passing data.
First is Custom Delegate
Second is NSNotification
Here we have two view controllers.
ViewController
and
SecondViewController
in SecondViewController
.h
#import <UIKit/UIKit.h>
#class SecondViewController;
#protocol SecondViewControllerDelegate <NSObject>
- (void)secondViewController:(SecondViewController *)secondViewController didEnterText:(NSString *)text;
#end
#interface SecondViewController : UIViewController
#property (nonatomic, assign)id<SecondViewControllerDelegate> delegate;
#property (nonatomic, strong) IBOutlet UITextField *nameTextField;//It must connect as outlet connection
- (IBAction)doneButtonTapped:(id)sender;
#end
.m
#import "SecondViewController.h"
#interface SecondViewController ()
#end
#implementation SecondViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
}
//Either use NSNotification or Delegate
- (IBAction)doneButtonTapped:(id)sender;
{
//Use Notification
[[NSNotificationCenter defaultCenter] postNotificationName:#"passingDataFromSecondViewToFirstView" object:self.nameTextField.text];
//OR Custom Delegate
[self.delegate secondViewController:self didEnterText:self.nameTextField.text];
[self.navigationController popViewControllerAnimated:YES];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
in ViewController
.h
#import <UIKit/UIKit.h>
#import "SecondViewController.h"
#interface ViewController : UIViewController<SecondViewControllerDelegate>
#property (nonatomic, strong) IBOutlet UILabel *labelName; //You must connect the label with outlet connection
- (IBAction)gotoNextView:(id)sender;
#end
.m
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
//addObserver here...
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(textFromPreviousViewControllerNotificationReceived:) name:#"passingDataFromSecondViewToFirstView" object:nil];
// Do any additional setup after loading the view, typically from a nib.
}
//addObserver Method here....
- (void)textFromPreviousViewControllerNotificationReceived:(NSNotification *)notification
{
// set text to label...
NSString *string = [notification object];
self.labelName.text = string;
}
- (IBAction)gotoNextView:(id)sender;
{
//If you use storyboard
SecondViewController *secondViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"SecondViewController"];
//OR If you use XIB
SecondViewController *secondViewController = [[SecondViewController alloc] initWithNibName:#"SecondViewController" bundle:nil];
secondViewController.delegate = self;
[self.navigationController pushViewController:secondViewController animated:YES];
}
//Calling custom delegate method
- (void)secondViewController:(SecondViewController *)secondViewController didEnterText:(NSString *)text
{
self.labelName.text = text; //Getting the data and assign the data to label here.
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
For your understanding the code I create a simple passing data from one second view controller to first view controller.
First we navigate the view from first view controller to second view controller.
After that we send the data from second view controller to first view controller.
NOTE : You can either use NSNotification or Custom Delegate method for sending data from One View Controller to Other View Controller
If you use NSNotification, you need to set the postNotificationName for getting data in button action method.
Next you need to write addObserver in (sending data to your required View Controller) ViewController and call the addObserver method in same View Controller.
If you use custom delegate,
Usually we go with Custom Protocol Delegate and also we need to Assign the delegate here.
Very importantly we have to set the Custom Delegate Method in the Second View Controller.Because where we send the data to first view controller once we click the done button in second view controller.
Finally we must call the Custom Delegate Method in First View Controller, where we get the data and assign that data to label.Now you can see the passed data using custom delegate.
Likewise you can send the data to other view controller using Custom Delegate Methods
I tried and got the solution for passing the value between viewcontroller.
MainViewController *mainVC = [[self storyboard] instantiateViewControllerWithIdentifier:#"MainViewController"];
mainVC.userId = #"539897197";
[self presentViewController:mainVC animated:YES completion:Nil];
or using this way . You don`t use the storyboard use the following its working fine
MainViewController *mainVC = [[MainViewController alloc] init];
mainVC.userId = #"539897197";
[self presentViewController:mainVC animated:YES completion:Nil];