I've two modal controllers with button close at the top navigation bar of each.
I want to intercept the correct close button in my main view controller.
Unfortunately this code doesn't work, why ?
- (IBAction)close:(UIStoryboardSegue *)sender {
if ([sender.identifier isEqualToString: #"FirstModalClose"]) {
NSLog(#"FirstModalClose");
}
if ([sender.identifier isEqualToString: #"SecondModalClose"]) {
NSLog(#"SecondModalClose");
}
}
Actually, the type IBAction suggest that this method is triggered (if at all) by a GUI element, not a segue. Thus, the sender is propably an UIControl not an UIStoryboardSegue.
Maybe you want use UIViewController's method - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender. There, you get both: the sender and the segue.
I simply had to insert FirstModalClose and SecondModalClose in the proper fields :(
I inserted FirstModalClose and SecondModalClose in Storyboard Segue and not in Storyboard Unwind Segue.
Now all work properly.
Related
I am writing a Cocoa Mac app in Objective-C and using Storyboard for my UI.
I have a "Confirm" button in my sheetViewController.m which I want to perform some action (save some settings) as well as dismiss the sheetViewController at the same time. They both use the sheetViewController.m as outlets.
Unfortunately, with Storyboard, I can only pick one received action (IBAction) or dismissController.
I want to perform the IBAction FIRST, before dismissing the sheet. How can I accomplish this?
Happy to do this in code as well instead of Storyboard if necessary!
Thanks!
You can use codes to dismiss controller in your IBAction.
I found out how to reference Storyboard ID in code:
On MainViewController:
- (IBAction)didClickButton:(NSButton *)sender {
SheetViewController *sheetViewController = [self.storyboard instantiateControllerWithIdentifier:#"SheetViewController"];
// Must match Storyboard ID
[self presentViewControllerAsSheet:sheetViewController];
}
On SheetViewController:
- (IBAction)didClickButton:(NSButton *)button {
// Do something
[self dismissViewController:self];
}
i am trying to send the view to next view but when i try to come back to the root page it crashes and say that Navigation Bar subview tree might get corrupted issue
- (IBAction)nxtBtn:(id)sender {
//here i am sending it to next view...
[self performSegueWithIdentifier:#"next" sender:(id)sender];
}
//function for segue
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
//next is the name of the identifier
if ([segue.identifier isEqualToString:#"next"]) {
nextViewController *vc=(nextViewController *)segue.destinationViewController;
vc.str=sender;
}
}
we don't need any kind of identifier for simple use of segue i.e. navigating from one view to another without passing any data. just simple as that you have to connect the segue from one view to other and run the application. it will work properly.
I have a the first application controller, MAViewControllerMenu, and when that controller loads, I already allocate the next controller, imageControllerView.
- (void)viewDidAppear{
[super viewDidAppear:(YES)];
if (!imageControllerView)
imageControllerView = [[self storyboard] instantiateViewControllerWithIdentifier:#"chosenImageController"];
}
Then, I select an image from the image picker, and want to move to the next controller,imageControllerView, where the image would be displayed. I set the next window's image property as follows:
imageControllerView.image = [[self.pageViews objectAtIndex:(centered_image_ind)] image];
This line works, I checked that there's a value in imageControllerView.image.
However, when I move to the next controller,imageControllerView , I notice that the memory address of imageControllerView changes, or in other words, imageControllerView's properties that I change before moving to that controller, specifically image, reset when I move there.
Instead of throwing code here, I was hoping you could let me know what I should provide.
I think it's a common problem people know of:
Controller's objects re-init'ing when moving from one controller to another.
Here's a screen shot that might give a hint of what Im trying to do
Left most one is where I select pictures which in turn go into the slide show scrollview. Then I click next, and the image is supposed to appear in the centered ImageView
Thanks
OK...
You cannot "already allocate the next view controller" this won't work. There is no point in creating it like this at all. You can delete the imageViewController property (or iVar) completely.
The arrows that you have between the view controllers in your storyboard are segues. In Interface Builder you can select a segue and give it an identifier. For instance you would use something like #"ImageViewSegue".
I guess the segue is attached to the Next button. This is fine.
Now, in your MAViewControllerMenu you need to put this method...
- (void)prepareForSegue:(UIStoryBoardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"ImageViewSegue"]) {
// the controller is CREATED by the segue.
// the one you create in view did load is never used
ImageViewController *controller = segue.destinationController;
controller.image = [[self.pageViews objectAtIndex:(centered_image_ind)] image];
}
}
Now for the segues in the other direction...
You appear to be using segues to dismiss the modal views. You can't do this. What it will do is create a new view controller and present that instead of dismissing the presented view.
i.e. you'll go...
A -> B -> C -> B -> A -> B
// you'll now have 6 view controllers in memory
// each segue will create a fresh view controller with no values set.
What you want is...
A -> B -> C
A -> B
A
// now you only have one view controller because the others were dismissed.
// when you dismiss a view controller it will go back to the original one.
// the original one will have all the values you set previously.
To do this you need to create a method something like...
- (IBAction)dismissView
{
[self dismissViewControllerAnimated:YES completion:nil];
}
Then whatever the button is for your dismiss action attach it to this method.
Now delete all the backwards curly segues.
Passing info back
To pass info back to the original view controller you need a delegation pattern or something similar.
You can read more about creating a delegate at This random Google Search
Create a delegate method something like...
- (void)imageViewSelectedImage:(UIImage *)image;
or something like this.
Now when you do prepareForSegue you can do...
controller.delegate = self;
and have a method...
- (void)imageViewSelectedImage:(UIImage *)image
{
// save the method that has been sent back into an array or something
}
I might be wrong, but seems you go to your second view controller using a segue, it is normal your controller instance isn't the same than the one retrieved by [[self storyboard] instantiateViewControllerWithIdentifier:#"chosenImageController"]
you should take a look at - (void) prepareForSegue:(UIStoryboardSegue *)segue
(UIViewController method)
inside this method set your image property to the segue destination controller (check the identifier of the segue)
I'm adding TabBarItem (Email) dynamically. When I finish with my email, I'm calling 'dismissModalViewControllerAnimated' but it's simply dismissing mail view. How do I unload the view controller?
in my email view controller I'm doing following:
- (void)viewDidLoad => I would like to unload this view controller
{
[super viewDidLoad];
[self showEMail:nil]; => this display and dismisses email (I'm not calling present.. and dismiss... in a row. I'm using delegate methods to present and dismiss, which is fine.)
[self presentModalViewController:picker animated:YES];
[self dismissModalViewControllerAnimated:YES];
}
after selecting my tab bar item, it's loading view controller(Lets say 'ABC View controller') which is presenting my mail modal controller. mail modal controller is being dismissed properly. but I would like to come back to previously selected tab item after unloading the 'ABC view controller'. is it possible? or am i doing something wrong here?
Thanks in advance
Rama
Rama, your question is hard to understand. maybe you need to use delegation for the view controller you are presenting.
In your code, calling [self presentModalViewController...] and [self dismissModalViewController...] in a row doesn't make sense.
You shall call the [self presentModalViewController...] in the first place, make the presenting view controller as the delegate (picker.delegate = self, for instance)
let the modal view controller do its business including exiting (like user hits cancel, close or whatever), then call the delegation method (something like [delegate didFinish...] or [delegate didCancel...]
now it's the presenting view controller's turn to response to the delegation method calling, you can do the modal view controller dismissing here
Note: many UIKit classes practice this pattern, such as UIAlertView, UIActionSheetView, MPMoviePlayerViewController, etc. You shall check them and make your own
I've solved problem by using ViewWiilAppear method to display mail modal presenter.
and i'm selecting the index of tab bar controller after dismissing mail modal presenter.
self.tabBarController.selectedIndex =0;
This solved my problem.
Cheers
I'm working on this tutorial, which shows how to create an app with storyboards. My viewController has two UIButtons and I have connected a segue to those UIButtons. These segues push a new viewController.
Now I am looking for a way to cancel this segue if a certain condition becomes true. When I used the old xib files to create my interface I was able to do something like this:
-(IBAction)sendButton:(id)sender {
if(TRUE) {
// STOP !!
}
}
This does not work anymore. How can I cancel the push of the new viewController?
Nope. You can't cancel segues that are directly linked to interface elements like your UIButton.
But there is a workaround.
Remove the segue that is linked to the button
Add a segue from the viewController (the one with the button) to the viewController that should be pushed. This must be a segue that is not connected to a interface element. To do this you can start the segue from the status bar. Or create the segue in the left sidebar.
Select this segue, open the attributes inspector and change the Identifier of the segue (e.g. PushRedViewController)
Select Xcodes assistant view, so you can see the .h file of the viewController with the button.
Connect the button to an action. To do this select the button and control-drag to the .h file. Select action in the menu and name your action (e.g. redButtonPressed:)
Open the implementation of your viewController
change the action from step 5 to something like this:
- (IBAction)redButtonPressed:(id)sender {
[self performSegueWithIdentifier:#"PushRedViewController" sender:sender];
}
You can actually do this by adding following method into your code
- (BOOL)shouldPerformSegueWithIdentifier:(NSString *)identifier sender:(id)sender {
if([identifier isEqualToString:#"btnSegue"])
{
return YES;
}
else{
return NO;
}
}
Lets assume your segue is btnSegue.And if you need the segue to be performed based on some condition you can have following code
if(check)
{
[self performSegueWithIdentifier:#"btnSegue" sender:self];
}
Where check is BOOL which you can set true or false based on your condition.