Passing Data between ViewController without using Segue - ios

I know the question is repeated, but requirement is little different so posting here. I know how to pass value from one ViewController to other by defining property to hold the value passed from first ViewController. I am attaching the ScreenShot for better understanding. What I did is embed a UIPageViewControllerinto NavigationController(SwipeBetweenViewController). From UIPageViewController calling UIViewController(ProfileViewController) programmatically. After clicking LOG IN button, getting some response, storing it in a variable. Now what I have to do is pass that variable to ProfileViewController.I have defined a property in ProfileViewController.h, imported ProfileViewController.h into LoginViewController.m. I am passing data directly between LoginViewController to ProfileViewController, should it be passed from UiPageViewController. Here is the code, I have tried but its not working. Execution control remains on the same page, no navigation.
ProfileViewController.h
#interface KKProfileViewController : UIViewController
#property(copy, nonatomic) NSString *userEmailId;
#end
LoginViewController.m
-(void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
{
if (error) {
// Handle error
}
else {
NSError *tempError;
NSDictionary* response=(NSDictionary*)[NSJSONSerialization JSONObjectWithData:receivedData options:kNilOptions error:&tempError];
NSString *loginResponse =response[#"message"];
_emailId =response[#"email"];
if ([loginResponse isEqualToString:#"Welcome"])
{
[self passLoginDataForward];
[self performSegueWithIdentifier:#"loginSuccess" sender:self];
}
else
{
//code for error alert
}
NSLog(#"Response is :%#", response);
}
}
-(void)passLoginDataForward
{
ProfileViewController *viewControllerProfile =[self.storyboard instantiateViewControllerWithIdentifier:#"profileViewController"];
viewControllerProfile.userEmailId = _emailId;
NSLog(#"user Email %#", viewControllerProfile.userEmailId);
[self.navigationController pushViewController:viewControllerProfile animated:YES];
}
SwipeViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
[[UINavigationBar appearance] setBarTintColor:[UIColor whiteColor]];
self.navigationBar.translucent = YES;
firstVC = [self.storyboard instantiateViewControllerWithIdentifier:#"profileViewController"];
secondVC = [self.storyboard instantiateViewControllerWithIdentifier:#"dashboardViewController"];
thirdVC = [self.storyboard instantiateViewControllerWithIdentifier:#"newsViewController"];
viewControllerArray = [[NSMutableArray alloc]init];
viewControllerArray = #[firstVC,secondVC,thirdVC];
self.currentPageIndex = 0;
self.isPageScrollingFlag = NO;
self.hasAppearedFlag = NO;
}
-(void)setupPageViewController
{
pageController = (UIPageViewController*)self.topViewController;
pageController.delegate = self;
pageController.dataSource = self;
[pageController setViewControllers:#[[viewControllerArray objectAtIndex:0]] direction:UIPageViewControllerNavigationDirectionForward animated:YES completion:nil];
[self syncScrollView];
}

The problem is because your login view controller may not have a navigation controller and you are trying to push view controller. Nothing will happen in this case.
If you want to push the page view controller to login views navigation stack, embed your login view controller in a navigation controller(Select login view controller Editor>Ember>Navigation controller) And add a segue to pageviewcontroller(directly from login view controller, not from any button). Add an identifier for the segue(say yourSegueID) Then implement the following method
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"yourSegueID"]) {
UIPageViewController *pageViewController = [segue destinationViewController];
ProfileViewController *viewControllerProfile =[self.storyboard instantiateViewControllerWithIdentifier:#"profileViewController"];
viewControllerProfile.userEmailId = _emailId;
[pageViewController setViewControllers:#[viewControllerProfile] direction:UIPageViewControllerNavigationDirectionForward animated:NO completion:nil];
}
}
Then call
[self performSegueWithIdentifier:#"yourSegueID" sender:nil];
Second option
If you want to create new navigation stack, as in your current storyboard implementation, make the segue from login view controller to navigation controller a present modal segue then change following line in prepareForSegue
UIPageViewController *pageViewController = [segue destinationViewController];
to
UINavigationController *navController = [segue destinationViewController];
UIPageViewController *pageViewController = navController.viewControllers[0];
Update
Updating as per your new code for swipeviewcontroller
In this case, You have to add email property in swipe view controller too. Then set it in prepare for segue method. Then set profile view controllers property in the swipe view controller viewdidload

-(void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
{
if (error)
{
// Handle error
}
else
{
NSError *tempError;
NSDictionary* response=(NSDictionary*)[NSJSONSerialization JSONObjectWithData:receivedData options:kNilOptions error:&tempError];
NSString *loginResponse =response[#"message"];
_emailId =response[#"email"];
///////////////////////
//set your Email in nsuserdefaults
[NSUserDefaults standardUserDefaults][setObject:_emailId forKey:#"email"];
[[NSUserDefaults standardUserDefaults]synchronize];
///////////////////////
if ([loginResponse isEqualToString:#"Welcome"])
{
[self passLoginDataForward];
}
else
{
//code for error alert
}
NSLog(#"Response is :%#", response);
}
}
-(void)passLoginDataForward
{
ProfileViewController *viewControllerProfile =[self.storyboard instantiateViewControllerWithIdentifier:#"profileViewController"];
[self.navigationController pushViewController:viewControllerProfile animated:YES];
}
Get Value in ProfileViewController.m
-(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
userEmailId = [[NSUserDefaults standardUserDefaults]objectForKey:#"email"];
}

UIStoryboard *storyboard = [UIStoryboard storyboardWithName:storyboardName bundle:nil];
YourViewController * vc = [storyboard instantiateViewControllerWithIdentifier:#"identifier"];
vc.something = something;
[self.navigationController pushViewController:vc animated:YES];
Use this instead of self.storyboard.

Related

Hide LoginViewController or dismiss to parentView

This is a normal LoginView calling on a specific action in my app
sourceViewVontroller
if ([password length] == 0) {
loginViewController *seatView = [mainStory instantiateViewControllerWithIdentifier:#"loggingView"];
[self presentViewController:login animated:YES completion:nil];
}
it checks if user not signed in yet when he's calling this action, so it redirects him to the loginViewController, then
loginViewController
UIStoryboard *mainStory = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
DestinationViewController *Dest = [mainStory instantiateViewControllerWithIdentifier:#"destView"];
[self presentViewController:Dest animated:YES completion:nil];
it goes to the destinationView that needs a login, now my problem is how to go back (dismiss not presentmodalView) to the sourceViewController, or simply, how to remove the loginViewController from the queue on success and dismiss directly to the source?
destinationViewController
// Tried to use presentView .. but i dont need to reload sourceView, just dismiss to it !
//[self presentViewController:srcView animated:YES completion:NULL];
//This is what am doing ..
[self dismissViewControllerAnimated:NO completion:nil];
Or just let me know if there is other professional way to do this login flow
I suggest for you another way:
First in - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
You will check user login or not. If login you will set rootView to destinationViewController. If not set rootView to loginViewController
SampleCode:
UIStoryboard *mainStory = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
if (logged) {
DestinationViewController *Dest = [mainStory instantiateViewControllerWithIdentifier:#"destView"];
self.window.rootViewController = Dest;
} else {
LoginViewController *seatView = [mainStory instantiateViewControllerWithIdentifier:#"loggingView"];
self.window.rootViewController = seatView;
}
When logout you just call notification or delegate set rootViewController of window to loginViewController.
Do not use presentViewController for bringing login controller.
Complete Process :
In Singleton class. set a global property.
#property (assign)BOOL isUserLoggedIn;
When user logs in or logs out, set this variable to true or false.
Set an enum in LoginViewController.
typedef enum {
DestViewControllerOne =1,
DestViewControllerTwo
} SignInType;
In this enum, put all your view controller where you wanna put that login check.
Set a property in login view controller to hold source controller value -
#property (nonatomic, assign) NSInteger signInType;
Set up a delegate in login controller to redirect after successfull login -
#protocol SignInProtocolDelegate <NSObject>
#optional
-(void) signInSuccess:(NSInteger) signInType;
#end
Create a property with that delegate in login controller -
#property (nonatomic, assign) NSObject<SignInProtocolDelegate>* delegate;
Now before proceeding to required view controller, perform below check -
if(![[TESingleton shareData] isUserLoggedIn]){
[self funcNavigateToSignInWithAlert:YES withSignInType:proceedToDestViewControllerOne];
}
else
{
[self proceedToDestViewControllerOne];
}
-(void)funcNavigateToSignInWithAlert:(BOOL)showAlert withSignInType:(NSInteger) signIntype
{
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:STORYBOARDNAME bundle:nil];
LoginViewController *viewController = (LoginViewController *)[storyboard instantiateViewControllerWithIdentifier:#"LoginViewController"];
[viewController setSignInType:signIntype];
[viewController setDelegate:self];
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:viewController];
navController.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
[[SlideNavigationController sharedInstance] presentViewController:navController animated:YES completion:nil];
}
By this, it will bring login page.
Next -
After successfull login, Do this in login controller :
[self dismissViewControllerAnimated:YES completion:nil];
[[self delegate] signInSuccess:self.signInType];
Import login delegate method in source controller that we have written above -
-(void) signInSuccess:(NSInteger) signInType
{
switch (signInType)
{
case DestViewControllerOne:
[self performSelector:#selector(proceedToDestViewControllerOne) withObject:nil afterDelay:0.5];
break;
case DestViewControllerTwo:
[self performSelector:#selector(proceedToDestViewControllerTwo) withObject:nil afterDelay:0.5];
break;
default:
break;
}
}
Implement these methods in source view controller -
-(void) proceedToDestViewControllerOne
{
//Restricting navigation to signin
//Addded by vikas Jul 8,2015
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:STORYBOARDNAME bundle:nil];
DestViewcontrollerOne *objDestViewcontrollerOne = (DestViewcontrollerOne *)[storyboard instantiateViewControllerWithIdentifier:#"DestViewcontrollerOne"];
[self.navigationController objDestViewcontrollerOne animated:YES];
}
This is complete process.
Use Unwind Segues
Add a method in SourceViewController
For Swift
#IBAction func unwindToThisViewController(segue: UIStoryboardSegue) {
}
For Objective-C
- (IBAction)unwindToThisViewController:(UIStoryboardSegue *)unwindSegue {
}
You can come back to the SourceViewController in two ways.
Using Storyboard e.g when an UIButton action fires.
Using performSegueWithIdentifier in code.
Storyboard:
Control drag form an UIButton in DestinationViewController to Exit segue inSourceViewController
In Code:
Control drag form an UIButton in DestinationViewController to Exit segue inSourceViewController
Call performSegueWithIdentifier:#"ExitToSourceViewController" when need to come back to SourceViewController

iOS use the delegate pass value not trigger the method

I was test the delegate pass the value in objective-c.
I know there are other methods can pass string between UIViewControllers like NSNotifyCenter..etc.
Now I want to try to use the delegate pass value .
But I encounter some problems.
I use the navigation and there have two UIViewController(FirstUIViewcontroller and SecondUIViewController).
Now I want to use manual to change to SecondUIViewController,not use the button drag to the SecondUIViewController at FirstUIViewController.
So I add the code in the FirstUIViewController.m button action.
- (IBAction)pushBtnAction:(id)sender {
SecondViewController *controller = [self.storyboard instantiateViewControllerWithIdentifier:#"SecondViewController"];
[self.navigationController pushViewController:controller animated:YES];
}
Then I want to pass the value from the SecondUIViewcontroller when I pop the view controller.
So I add the delegate implement and se the delegate in the FirstUIViewController.m.
- (void)viewDidLoad {
[super viewDidLoad];
UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:#"Main" bundle: nil];
secondVC = (SecondViewController*)[mainStoryboard instantiateViewControllerWithIdentifier:#"SecondViewController"];
secondVC.delegate = self;
}
-(void) passSecondVC:(SecondViewController *)vc didAddValue:(NSString *)str
{
NSLog(#"second str:%#",str);
}
In the SecondUIViewController.h , I had declare delegate method.
#class SecondViewController;
#protocol SecondViewControllerDelegate <NSObject>
#optional
-(void)passSecondVC:(SecondViewController*)vc didAddValue:(NSString*) str;
#end
#interface SecondViewController : UIViewController
#property (nonatomic,assign) id<SecondViewControllerDelegate> delegate;
- (IBAction)passValueDelegatBtnAction:(id)sender;
In the SecondViewController.m ,
when I click the button will pop self uiviewcontroller and pass the value to FirstUIViewController.
- (IBAction)passValueDelegatBtnAction:(id)sender {
if( [self.delegate respondsToSelector:#selector(passSecondVC:didAddValue:)])
{
[self.delegate passSecondVC:self didAddValue:#"this is string from sencond vc"];
}
[self.navigationController popViewControllerAnimated:YES];
}
(My problems)
But in this status , I always can't get the value in the delegate method in the FirstUIViewController.
I had try to other method like below in the FirstViewController.m
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
NSLog(#"segue");
id vc = segue.destinationViewController;
if( [vc isKindOfClass:[SecondViewController class]])
{
SecondViewController *secondVC = vc;
secondVC.delegate = self;
}
}
There are same problem.
I can't get the value from the delegate method.
Have anyone know where the problems?
I post my completely code in here.
Thank you very much.
Alright!
Remove your code from the viewDidLoad: method and set the delegate when you push the secondViewController.
- (IBAction)pushBtnAction:(id)sender {
SecondViewController *controller = [self.storyboard instantiateViewControllerWithIdentifier:#"SecondViewController"];
[controller setDelegate:self];
[self.navigationController pushViewController:controller animated:YES];
}
So what was going wrong?
Ans: You create a new object in your viewDidLoad: method and set your firstViewController as delegate to it. Now while pushing you are creating another object of SecondViewController whose delegate is not set.
I downloaded your code & fixed it.
You don't want this line. so comment it,
// UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:#"Main" bundle: nil];
// secondVC = (SecondViewController*)[mainStoryboard instantiateViewControllerWithIdentifier:#"SecondViewController"];
// secondVC.delegate = self;
Edit this method as below,
- (IBAction)pushBtnAction:(id)sender {
SecondViewController *controller = [self.storyboard instantiateViewControllerWithIdentifier:#"SecondViewController"];
controller.delegate = self;
[self.navigationController pushViewController:controller animated:YES];
}
Also edit this method as below,
- (IBAction)passValueDelegatBtnAction:(id)sender {
// if( [self.delegate respondsToSelector:#selector(passSecondVC:didAddValue:)])
// {
[self.delegate passSecondVC:self didAddValue:#"this is string from sencond vc"];
// }
[self.navigationController popViewControllerAnimated:YES];
}
you forgot some code in pushBtnAction..
- (IBAction)pushBtnAction:(id)sender {
SecondViewController *controller = [self.storyboard instantiateViewControllerWithIdentifier:#"SecondViewController"]; // It's different to VC you init in viewDidLoad
controller.delegate = self; // you forgot....
[self.navigationController pushViewController:controller animated:YES];
}
prepareForSegue be call when you use segue to navigation.

how to navigation using segue?

I have to navigate to next screen on button click using segue,but the condition is i call a web service ,if the result from web service is SUCCESS it should navigate else stay in the loginscreen. But using the below code it simply navigates ..
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if([[segue identifier] isEqualToString:#"loginbutton"])
{
[self.sharedController setLoginDetailsDyanamic1:_strUsername.text password:_strPassword.text delegate:self];
if ([[dictresult objectForKey:#"Response"] isEqual: #"Success"])
{
DashBoardViewController *obj = [[DashBoardViewController alloc]init];
[self.navigationController pushViewController:obj animated:YES];
}
}
}
//delegates
-(void)controllerDidFinishLoadingWithResult:(id)result;
{
dictresult = result;
NSLog(#" result ----- :%#",dictresult);
NSLog(#" result of key----- :%#",[dictresult objectForKey:#"Response"]);
// if ([[result objectForKey:#"Response"] isEqual: #"Success"])
// {
// DashBoardViewController *obj = [[DashBoardViewController alloc]init];
// [self.navigationController pushViewController:obj animated:YES];
//
// }
}
-(void)controllerDidFailLoadingWithError:(NSError*)error;
{}
The result that i get in -(void)controllerDidFinishLoadingWithResult:(id)result is:
result ----- :{
Response = Success;
Token = 2e8c0ef66a5ac15b8f61da080c26d056218a6172;
errorCode = 0; }
How do i manage this? I have wired my button with the next view.
You have to set a Segue Identity on your storyboard then use this line of code to Segue to the next view controller.
[self performSegueWithIdentifier:#"SegueIdentity" sender:self];

Attempting to begin modal transition while transition is in progress

I'm trying to check if a user is logged into Facebook. If they are, I want to transfer them to another view.
The issue I'm having is that loginViewFetchedUserInfo and loginViewShowingLoggedInUser are both called before the view is actually done loading.
Because of this, when [self showWelcome:self] is called, I get a "attempting to begin modal transition while transition is in progress" error.
I can't seem to figure out a way to wait until the view is done loading before sending them off to the new view.
- (void)loginViewShowingLoggedInUser:(FBLoginView *)loginView {
// Set flag
isFirstLoginDone = YES;
NSLog(#"User is logged in");
}
- (void)loginViewFetchedUserInfo:(FBLoginView *)loginView
user:(id<FBGraphUser>)user {
// Check first login
if(isFirstLoginDone) {
[self showWelcome:self];
}
// clear the flag
isFirstLoginDone = NO;
}
- (IBAction)showWelcome:(id)sender
{
UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:#"WelcomeStoryboard" bundle:nil];
UIViewController *vc = [mainStoryboard instantiateViewControllerWithIdentifier:#"WelcomeController"];
[self presentViewController:vc animated:YES completion:nil];
}
Yes , it happens when you present some another viewController while a viewController is being present. For that create a dummy method as below code and fire it with small time intervals.
- (IBAction)showWelcome:(id)sender{
[self someMethod];
}
-(void)someMethod{
if(self.isBeingPresented){
[self performSelector:#selector(someMethod) withObject:nil afterDelay:.1];
}
else{
UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:#"WelcomeStoryboard" bundle:nil];
UIViewController *vc = [mainStoryboard instantiateViewControllerWithIdentifier:#"WelcomeController"];
[self presentViewController:vc animated:YES completion:nil];
}
}

Objective C, crash when dismissViewControllerAnimated

my apps is crashing when i dismiss from modal view. Here is my code
BaseViewController -
- (MFSideMenuContainerViewController *)menuContainerViewController {
return (MFSideMenuContainerViewController *)self.navigationController.parentViewController;
}
-(void) setup
{
BaseViewController *baseViewController = [[BaseViewController alloc] initWithNibName:#"BaseViewController" bundle:nil];
UINavigationController *navigationController = self.menuContainerViewController.centerViewController;
NSArray *controllers = [NSArray arrayWithObject:baseViewController];
navigationController.viewControllers = controllers;
}
- (void)call
{
PopUpViewController *popUpViewController = [[PopUpViewController alloc] init];
[popUpViewController setModalTransitionStyle:UIModalTransitionStyleCoverVertical];
[self presentViewController:popUpViewController animated:NO completion:nil];
}
PopUpViewController -
-(void) close {
if([NSThread isMainThread]) {
[self dismissViewControllerAnimated:YES completion:nil];
}
else
{
[self performSelectorOnMainThread:#selector(close)
withObject:nil
waitUntilDone:YES];
}
}
When execute "setup" > "call" function, it's switch to PopUpViewController. When i try to trigger "close" function from PopUpViewController and it crash. It only happen on IOS7 other than that is just fine.
i got this error message from Zombie Object
-[BaseViewController respondsToSelector:]: message sent to deallocated instance 0x15e8e050
UPDATE **
I had changed my mind, instead of create a new instance for navigationController, i just setup a new View for baseViewController and it won't crash anymore.

Resources