I am using a standard "show" segue in storyboard for a transition between two view controllers.
In the second VC, there is a method in viewWillAppear that fires a progress bar that is appearing during the segue and marring its appearance.
Is there any way to detect that the segue is in progress so that I can delay the progress bar until after the segue is complete?
I know I could move the progress bar to a later point in the lifecycle of the second view controller such as viewDidAppear but in most cases, the VC is reached without this particular segue and I would like the progress bar to fire immediately. If in the midst of the segue, however, I'd like to delay it.
Note: these are garden variety show Segues with animation in Storyboard, not custom segues.
You can define a public method for fire the progress bar and call it from first VC.
Here is the implementation of this approach:
In FirstVC.m:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
// set segu identifier to SecondVC in StoryBoard
if ([segue.identifier isEqualToString:#"SecondVC"]) {
SecondVC *secondVC = (SecondVC *)segue.destinationViewController;
[secondVC fireProgressBar];
}
}
In SecondVC.h:
#import <UIKit/UIKit.h>
#interface SecondVC : UIViewController
-(void)fireProgressBar;
#end
In SecondVC.m:
#import "SecondVC.h"
#implementation SecondVC
- (void)viewDidLoad {
[super viewDidLoad];
}
-(void)fireProgressBar {
NSLog(#"Progress Bar Fired!!!");
}
#end
Related
I have two view controllers inside a Navigation Controller.
In the first view controller I have two buttons. Both of them call the second view controller using a Push segue, but:
I need to know which button sent me in the second view controller. How?
In the second view controller I have a UIDatePicker and a Button "Ok": how can I send the chosen date to the first view controller when Ok is pressed? (And how do I receive them?)
EDIT:
I don't know if my problem is clear: now I know how to pass data from the first view controller to the second view controller with prepareForSegue, but what I really need is to pass data (the picked date) from the second view controller to the first, and how can I do it without a prepareForSegue (when Ok is pressed)?
EDIT2:
I made it. It was so simple, guys...
I decided to use modal segue:
Firstviewcontroller.h:
+(FirstViewController *)getInstance;
Firstviewcontroller.m:
static FirstViewController *instance =nil;
+(FirstViewController *)getInstance
{
return instance;
}
and in its ViewDidLoad:
instance = self;
Secondviewcontroller.m, in the OkButton IBAction:
SecondViewController *secondViewController = [SecondViewController getInstance];
//...
//modify what I need to modify in secondviewcontroller
//...
[self dismissModalViewControllerAnimated:YES];
That's it.
Thank you all anyway.
Assign Identifier to each segue in storyboard and implement
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
// Make sure your segue name in storyboard is the same as this line
if ([[segue identifier] isEqualToString:#"YOUR_SEGUE_NAME_HERE"])
{
// Get reference to the destination view controller
YourViewController *vc = [segue destinationViewController];
[vc setDelegate:self];
// Pass any objects to the view controller here, like...
[vc setMyObjectHere:object];
}
}
For more info about How to use storyboard and pass value check this article or this discussion on stackoverflow
for the second question you can use delegate pattern
IN SecondViewController.h
#protocol SomethingDelegate <NSObject>
- (void)dateChanged:(NSString *)dateStr; //you can use NSDate as well
#end
#interface ViewController2 : UIViewController
#property(weak) id<SomethingDelegate> delegate;
#end
in .m file
-(void) OkClicked{
[_delegate dateChanged:#"YOUR_DATE_VALUE"];
}
In FirstViewController.h
#import "SecondViewController.h"
#interface FirstViewController : UIViewController<SomethingDelegate>
in .m
-(void)dateChanged:(NSString *)dateStr{
// do whatever you need with dateStr
//also i made some change in prepareForSegue method
}
Note:- take care your naming convenes for VC
just pass the button id to the second viewcontrol.
use delegates to sent the data from second viewcontroller back to first view controller
regards
Johan
I'm new to iOS programming and I'm facing a problem
I'm having a problem with custom delegate.
I'm trying to make a simple custom where it return data to the previous view controller and pop the current view controller.
I have 2 navigation view controller
1 - main view controller
2 - Adding
and here is the protocol that is written in the adding view controller
#protocol AddingDelegate <NSObject>
#required
-(void)setInformation:(Adding *)controller withObject:(Conference *)info;
and here is the where I called it in adding view controller
-(IBAction)addingConference
{
NSLog(#"Adding Button Pressed");
conferenceObject = [[Conference alloc]init];
conferenceObject.name = [NameTX text];
conferenceObject.city = [CityTX text];
conferenceObject.description = [Dectription text];
NSMutableArray *info = [[NSMutableArray alloc] init];
[info addObject:conferenceObject];
[self.delegate setInformation:self withObject:conferenceObject];
NSLog(#"adding Conference method is done");
}
I wrote the delegate at the interface in the main view controller
#interface MainViewController : UITableViewController <AddingDelegate>
#end
and here where I declared the delegate method
-(void)setInformation:(Adding *)controller withArray:(NSMutableArray *)info
{
NSLog(#"in the main view at the delegate");
[self.navigationController popToRootViewControllerAnimated:YES];
NSLog(#"Should be popped right now");
}
and this is the prepare for segue method
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"AddObject"]) {
UINavigationController *navigation = segue.destinationViewController;
Adding *addingViewController = [[navigation viewControllers]objectAtIndex:0];
addingViewController.delegate = self;
}
}
now the problem is when I push the adding on top of the stack and then fill the information and press done the adding view controller doesn't pop to show main view controller.
I tried to log everything and the logs from the main view controller doesn't show .
Please help me
What I notice here is that in the implementation of prepareForSegue:sender: the segue's destinationViewController is a navigation controller. This makes me think that your segue is not pushing the AddingController on the current navigation stack but it's presenting a new one instead. This means the new navigation controller containing the AddingController is presented modally and as such, when you try to pop the navigation stack nothing seems to happen because you're operating on the wrong navigation stack. If that is the case you have two options: 1. change [self.navigationController popToRootViewControllerAnimated:YES]; for [self dismissViewControllerAnimated:YES completion:nil]; or 2. change the segue to be a push segue instead of a modal segue and point the segue directly to the AddingController.
In Adding.m
#class Adding;
#protocol AddingDelegate
- (void)flipsideViewControllerDidFinish:(FlipsideViewController *)controller;
#end
#interface Adding : UIViewController
#property (weak, nonatomic) id <AddingDelegate> delegate; // have you forgot this one
#end
and use
[self dismissViewControllerAnimated:YES completion:nil];
You need dismiss if you want get back to previous screen and make sure you have added Navigation controller
Does unwinding a storyboard segue in ios6 replace the need to make a source scene implement a delegate to pass data back from the child scene to the parent scene in ios5?
The way I usually do it is:
Parent Controller Header:
Call the Delegate of the child scene
#interface ParentViewController : UIViewController <ChildViewControllerDelegate>
//ok not much to show here, mainly the delegate
//properties, methods etc
#end
Parent Controller Main (body):
Prep the segue, set the delegate, create a return method from child scene
-(void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"toChildScene"])
{
UINavigationController *childViewController = segue.destinationViewController;
childViewController.delegate = self;
}
}
#pragma mark - Delegate Segue Methods
-(void) childViewControllerDidSave: (ChildViewController *) controller Notes:(NSString *)sNotes
{
someTextLabel.Text = sNotes
[self dismissModalViewControllerAnimated:YES];
}
Child Controller Header:
create the delegate, reference the parent scenes methods
#class ChildViewController;
#protocol ChildViewControllerDelegate <NSObject>
-(void) childViewControllerDidSave: (ChildViewController *) controller Notes:(NSString *)sNotes
#end
#interface ChildViewController : UIViewController
#property (weak, nonatomic) id <ChildViewControllerDelegate> delegate;
//properties, methods, etc
#end
Child Controller Main (body):
call the parent scenes method
- (IBAction)someAction:(id)sender
{
[self.delegate childViewControllerDidSave:self sNotes:someTextField.text];
}
So now the million Dollar question:
Is this process now simpler in iOS 6? Can I cut a lot of the work out using unwinding a segue / exit segue? Any example would be greatly appreciated.
Yes.
Unwind segues are an abstracted form of delegation. In iOS 6, it's simpler to use unwinds rather than delegates to pass data backwards when dismissing view controllers.
In the parent view controller, create an unwind method that returns an IBAction and takes a UIStoryboardSegue as the argument:
- (IBAction)dismissToParentViewController:(UIStoryboardSegue *)segue {
ChildViewController *childVC = segue.sourceViewController;
self.someTextLabel.Text = childVC.someTextField.text;
}
Then, in the child view controller, Control-drag from your dismiss button to the green exit icon to connect the unwind segue:
When doing a modal segue, does the originating ViewController get discarded after the segue is performed? I am setting the destination controller's delegate to the source ViewController, but when the destination ViewController.viewDidLoad, the self.delegate is nil...
The following code will produce the log message "ListViewController.viewDidLoad: My delegate is nil :("
[Source] MapViewController:
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if([segue.identifier isEqualToString:#"mapToList"]){
NSLog(#"MapViewController.prepareForSegue: Segue mapToList being called, setting LisViewController's delegate to myself");
[segue.destinationViewController setDelegate:self];
if(!self){
NSLog(#"MapViewController.prepareForSegue: I am nil.");
} else {
NSLog(#"MapViewController.prepareForSegue: I am NOT nil.");
}
}
}
[Destination] ListViewController:
- (void)viewDidLoad
{
[super viewDidLoad];
if(!self.delegate){
NSLog(#"ListViewController.viewDidLoad: My delegate is nil :(");
} else {
NSLog(#"ListViewController.viewDidLoad: My delegate populated");
}
}
Your code seems correct, the only thing I have done differently is test this in a skeleton framework I have that is a tableviewcontroller nested in a navigationcontroller. I just tested with the following code and it works fine for me:
RootViewController .h:
#interface RootTableViewController : UITableViewController <newTest>
Prepare for Segue (in rootViewController):
-(void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if ([segue.identifier isEqualToString:#"segueToModalView"]){
[segue.destinationViewController setDelegate:self];
}
}
Top of Modal View Controller .h:
#protocol newTest <NSObject>
-(void) hello;
#end
Property Declaration in Modal View:
#property (nonatomic, strong) id <newTest> delegate;
ViewDidLoad in Modal View:
- (void)viewDidLoad
{
[super viewDidLoad];
NSLog(#"%#", self.delegate);
}
My NSLog of self.delegate properly prints out and my code appears to be more or less the same as yours. Is your property declared correctly?
This is an old question but I came upon it when running into the same issue myself. Couple of things here:
To the guy who didn't understand why someone would want to use a Nav controller with a modal display - its to get the benefit of the nav bar without having to embed a UINavigationBar into your own view controller like tw airball did.
To solve the problem without resorting to what tw airball did remember that the destination view controller for the segue in this case is the navigation controller...not the view controller embedded in the nav.
So the fix is in your prepareForSeque:
UINavigationController *navController = segue.destinationViewController;
MyRealDestViewController *myRealDestViewController = (MyRealDestViewController)navController.topViewController;
myRealDestViewController.delegate = self;
If the segue is to a NavigationController then the destinationViewController loses the delegate.
I got around this problem by having the modal segue into the destinationViewController, and then adding NavigationBar and Bar Buttons to simulate the navigation controller (I assume you wrapped the destinationViewController in a NavigationController for the "done" and "cancel" buttons).
Set the delegate as normal in the rootViewController:
-(void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if ([segue.identifier isEqualToString:#"segueToModalView"]){
[segue.destinationViewController setDelegate:self];
}
}
Hope that helps
I'm trying to implement an iBooks-like flip transition as a storyboard. The segue should push resp. pop the destinationViewController onto/from the UINavigationControllers stack.
I can push viewcontrollers in my segues perform method but I am not able to pop. When I pop the controller right after creating my flip animation the animation does not run and its callback - that should perform [[UIApplication sharedApplication] endIgnoringInteractionEvents] gets never called and my App results dead.
So I tried to push/pop in the animationDidStop:anim:flag delegate method but it never gets called with the flag set to true.
I assume that the segue is deallocated before the delegate method gets called. What else could I do?
Forgive me if I am completely misunderstanding this question, but it seems like you just want to do a basic horizontal flip back and forth between two view controllers. And even if you've already figured this out, maybe it will help anyone else who has the same question.
(1) In your storyboard (that has ViewController A & B) create a Modal Segue from A to B. Give it an identifier (showViewControllerB) and choose Transition:Flip Horizontal.
We set up the protocol and delegates:
(2a) In ViewControllerB.h add above #interface:
#class ViewControllerB;
#protocol ViewControllerBDelegate
- (void)viewControllerBDidFinish:(ViewControllerB *)controller;
#end
(2b) Add the delegate as a property:
#property (weak, nonatomic) id <ViewControllerBDelegate> delegate;
(3a) In ViewControllerB.m synthesize:
#synthesize delegate;
(3b) And delegate in the method to flip back:
- (IBAction)flipBack:(id)sender
{
[self.delegate viewControllerBDidFinish:self];
}
(4) In ViewControllerA.h add at the very top #import "ViewControllerB.h" and on the end of #interface <ViewControllerBDelegate>
(5a) In ViewControllerA.m add the method to conform to the protocol:
- (void)viewControllerBDidFinish:(ViewControllerB *)controller
{
[self dismissModalViewControllerAnimated:YES];
}
(5b) Then set it as the delegate in prepareForSegue:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"showViewControllerB"]) {
[[segue destinationViewController] setDelegate:self];
}
}
I hope this answers your question. If I misunderstood, just let me know.
Your question is a bit confusing as so mingle pop, push, flip and backflip. I´m not sure if ai can answer your question, but i can tell what i did.
If i push a viewController into the navigation controller stack and set the Storyboard Segue Style to Push, it will be pushed into the view from right to left. A back button appears and shows the title of the presentingViewController in it.
If i set the Storyboard Segue Style to Modal i can set the Transition to Flip Horizontal (what seems to be what you want). But then no Back Button will appear. In the presentedViewController i dismiss the view with:
[self.presentingViewController dismissViewControllerAnimated:YES completion:nil];
It will flip the second view back with a right flip.
But this is the dirty solution and it is not recommended by apple.
http://developer.apple.com/library/ios/featuredarticles/ViewControllerPGforiPhoneOS/ManagingDataFlowBetweenViewControllers/ManagingDataFlowBetweenViewControllers.html#//apple_ref/doc/uid/TP40007457-CH8-SW9
Luke Dubert gave you an example how to implement the delegate.