Not able to perform segue back using storyboard - ios

I have started working with segue to perform navigation between viewcontrollers. This is how i was performing push segue from EPSearchResultController to destination viewcontroller.
//.h file
#property (strong, nonatomic) EPSearchResultController *obj_EPFirstViewController;
//.m File
- (IBAction)submitEPSearchQuery:(id)sender {
[self performSegueWithIdentifier:#"searchResultSegue" sender:sender];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"searchResultSegue"])
{
self.obj_EPFirstViewController = (EPSearchResultController*)[segue destinationViewController];
self.obj_EPFirstViewController.searchAgainDelegate = self;
NSDictionary* resultDict= [NSDictionary dictionaryWithContentsOfFile:[[NSBundle mainBundle]pathForResource:#"SearchResult" ofType:#"plist"]];
self.obj_EPFirstViewController.searchResultArray = [resultDict objectForKey:#"Result"];
}
}
Problem:
When i am moving back from my destination to EPSearchResultController its showing me black screen. I am moving back by using
#pragma mark - Search Again Delegate
-(void)moveBack{
[self.navigationController popViewControllerAnimated:YES];
}
Anybody having any idea why its showing me a black screen.

1) Check presentation style of a segue in Storyboard. It can be:
Push
Modal
Custom
2) Use correct dismiss method.
if Push, use [self.navigationController popViewControllerAnimated:YES]
if Modal, [self dismissViewControllerAnimated:YES completion:];

Thanks for your support...from your answers i got the idea that there is some problem with segue formation. I found it out that i made segue from button on EPSearchResultController to destination viewcontroller. But it should be from EPSearchResultController to destination viewcontroller. :-)

Related

ios Navigation can't pass value to next Viewcontroller when I popViewController again

I have two ViewController (ViewController, ResultViewController).
There have three button in the ViewController,and there have a back button in ResultViewController.
In the ResultViewController I want to get the value from the ViewController passing.
So I add the below code in the ResultViewController
#interface ResultViewController : UIViewController
- (IBAction)backEvent:(id)sender;
#property (weak, nonatomic) IBOutlet UILabel *resultLb;
#property (strong, nonatomic) NSString *selectedVal;
#end
.m
- (void)viewDidLoad {
[super viewDidLoad];
[self.navigationController setNavigationBarHidden:YES animated:NO];
self.resultLb.text = self.selectedVal;
}
- (IBAction)backEvent:(id)sender {
[self.navigationController popViewControllerAnimated:NO];
}
In the ViewController have three button action:
- (void)viewDidLoad {
[super viewDidLoad];
[self.navigationController setNavigationBarHidden:YES animated:NO];
rvc = [self.storyboard instantiateViewControllerWithIdentifier:#"ResultViewController"];
}
- (IBAction)passAEvent:(id)sender {
rvc.selectedVal = #"A";
[self.navigationController pushViewController:rvc animated:NO];
}
- (IBAction)passBEvent:(id)sender {
rvc.selectedVal = #"B";
[self.navigationController pushViewController:rvc animated:NO];
}
- (IBAction)passCEvent:(id)sender {
rvc.selectedVal = #"C";
[self.navigationController pushViewController:rvc animated:NO];
}
When I first click the button A, that can correct pass the "A" value to the ResultViewController.
But when I click the back button in the ResultViewController.
Then click the B or C button action, that still pass the "A" value.
I see the log, that was not enter B, C event.
I try to run again program, when I click the first button with B button, It was correct enter and pass "B" value to ResultViewController.
But when I click the back button, then click the A or C button, it was not correct value in the ResultViewController.It still show "B" value.
I don't know why? how can I resolve the problem if not use delegate or notify?
Thank you.
----- edit ----
To the #Gaurav Singh
I am not find the option about the animate .
It's because you're keeping a strong reference to the UIViewController, via your variable rvc.
You're setting the value of resultLb in the viewDidLoad method of your view controller. When you push the view controller onto the stack, your view controller's setting the label by taking what's stored in it's variable selectedVal.
When you pop the view controller from the stack, because you've got it stored in a variable, it won't get unloaded from memory. It still exists. You may be setting selectedVal again when tapping the second button, however viewDidLoad isn't going to get run again, as it's not getting re-instantiated.
What you could do is overload setSelectedVal on ResultViewController as follows:
- (void)setSelectedVal:(NSString *)selectedVal {
_selectedVal = selectedVal;
self.resultLb.text = selectedVal;
}
This way, when you set selectedVal from the calling view controller, the above method will be run, setting the value of your property in ResultViewController, whilst also modifying your label.
EDIT - Better still:
Rather than setting the value of the label in viewDidLoad:, do it in viewWillAppear: instead. This way, you don't need to override any setters or anything like that. When viewWillAppear is called, it'll read the string you've set and set the label's text accordingly.
Hope this helps!
You are just making it complex. I would do it like this:
First I will connect create a storyboard segue from ViewController to Result Controller (View Controller to View Controller segue) and assign a suitable identifier to that segue (say "resultSegue")
then following code would work
- (IBAction)passAEvent:(id)sender {
[self performSegueWithIdentifier:#"resultSegue" sender:#"A"];
}
- (IBAction)passBEvent:(id)sender {
[self performSegueWithIdentifier:#"resultSegue" sender:#"B"];
}
- (IBAction)passCEvent:(id)sender {
[self performSegueWithIdentifier:#"resultSegue" sender:#"C"];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue
sender:(id)sender {
if([segue.identifier isEqualToString:#"resultSegue"]){
ResultViewController *rvc = segue.destinationViewController;
rvc.selectedVal = sender; //Here SENDER will have value: A,B or C which we have passed in performSegueWithIdentifier:sender: method
}
}
Edit: code in prepareForSegue:sender: method modified so that it check the segue identifier before working on destinationViewController
First, you should give the segue an "id",like "resultSegue".
Then, use the code:
- (void)prepareForSegue:(UIStoryboardSegue *)segue
sender:(id)sender
{
if([segue.identifier isEqualToString:#"resultSegue"]){
ResultViewController *rvc = segue.destinationViewController;
rvc.selectedVal.text = someUILabel.text;
than use the [self.navigationController pushViewController:rvc animated:NO];//.........
}
I will give you more detail when I m at home, if you don`t solve the problem....
Thanks!
put
rvc = [self.storyboard instantiateViewControllerWithIdentifier:#"ResultViewController"];
in viewWillAppear

Custom Delegate Callback

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

iOS: dismiss popOver generated with Interface Builder with button within the popOver

I have a button which leads to a popOver, all created in Interface Builder. The popOver is closed when I press somewhere outside of it, but I would also like to implement a button within the popOver which does that.
I found a solution by Giorgio Barchiesi dating back to 2011, however I fail to implement it. Here's his solution:
In the implementation file of the source view controller:
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue destinationViewController] isKindOfClass:[MyDestViewController class]]) {
MyDestViewController* viewController = (MyDestViewController*)[segue destinationViewController];
UIStoryboardPopoverSegue* popoverSegue = (UIStoryboardPopoverSegue*)segue;
[viewController setPopoverController:[popoverSegue popoverController]];
}
}
In the header file of the destination view controller:
#property (weak, nonatomic) UIPopoverController* popoverController;
In the implementation file of the destination view controller:
#synthesize popoverController;
Same file, whenever you want to dismiss the popover:
[popoverController dismissPopoverAnimated:YES];
i could call the last function when the button is pressed.
My problem is that XCode gives me an error on the [viewController setPopoverController:[popoverSegue popoverController]] line: ARC Semantic Issue: No known class method for selector 'setPopOverController'
What did I miss to implement?
Here is the method I use:
Open your storyboard file, select the segue arrow and open the Attributes Inspector (Option - Command - 4) and identifier fill in a sensible name, like "myPopoverSegue".
In your Source View Controller define a variable right after #implementation :
#implementation ViewController
{
__weak UIPopoverController *myPopover;
}
Then, again in the Source VC:
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if ([segue.identifier isEqualToString:[dict objectForKey:#"myPopoverSegue"]]) {//#"segue" is your segue name. You can use isKindOfClass as you do currently, I prefer this method.
myPopover = [(UIStoryboardPopoverSegue *)segue popoverController];
}
}
-(void)closePopover{
[myPopover dismissPopoverAnimated:YES];
}
In the end of your Source VC's viewDidLoad method write:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(closePopover) name:#"popoverShouldDismiss" object:nil];
Finally, whenever you want to dismiss the popover:
[[NSNotificationCenter defaultCenter] postNotificationName:#"popoverShouldDismiss" object:nil];
Hope this helps!
This way you will also be able to change the segue to a different controller without changing your code.
You can add the delegate < UIPopoverControllerDelegate > to your class and override the delegate method:
- (BOOL)popoverControllerShouldDismissPopover:(UIPopoverController *)popoverController
{
return NO;
}
This will prevent the popover to be dismissed when user presses anywhere on screen.
Now you can dismiss your popover inside the button's selector method by using:
[popoverController dismissPopoverAnimated:YES];
In iOS 8 it's really easy. Just call
[self dismissViewControllerAnimated:YES completion:^{}];
Pop overs are regular presentation controllers, so it's more or less the exact same thing as a modal view controller.
Try this code
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue destinationViewController] isKindOfClass:[MyDestViewController class]])
{
MyDestViewController* viewController = (MyDestViewController*)[segue destinationViewController];
UIStoryboardPopoverSegue* popoverSegue = (UIStoryboardPopoverSegue*)segue;
popoverSegue.popoverController=[[UIPopoverController alloc] initWithContentViewController:viewController];
[popoverSegue.popoverController setPopoverContentSize:CGSizeMake(viewController.view.frame.size.width, viewController.view.frame.size.height)];
popoverSegue.popoverController.delegate=self;
[viewController setPopoverController:popoverSegue.popoverController];
}
}
I hope it helps you.

Segue to ABPersonViewController in Storyboard

I am trying to segue to a ABPersonViewController from a button in the Storyboard.
But if I do that the screen is completely black.
If I use a IBAction for the button and use the following code it works:
ABPersonViewController *person = [[ABPersonViewController alloc]init];
[self.navigationController pushViewController:person animated:YES];
Why is that? am I doing wrong?
EDIT: I found a work around but I don't think this is a proper way to do it. I subclassed ABPersonViewController and overrode the initWithCoder method with the following:
-(id)initWithCoder:(NSCoder *)aDecoder{
self = [self initWithNibName:nil bundle:nil];
return self;
}
Since you are using storyboards you should should name the segue you are using and then this in your IBAction:
[self performSegueWithIdentifier:#"abPersonViewControllerSegue" sender:self];
This way you do not even need to manually call alloc/init. Then in your prepareForSegue you could set any attributes:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"abPersonViewControllerSegue"])
{
[segue.destinationViewController setAttribute:#"whatever you want"];
...
}
}
If this is not what you are looking for please let me know.
You don't set the displayedPerson property ...
#property(nonatomic, readwrite) ABRecordRef displayedPerson
Since you are using Storyboard, why do you still call [[ABPersonViewController alloc]init]?The Storyboard will handle the creation and pushing of the ABPersonViewController(if you specified Push action for the segue). As long as you control dragged from the Button to the ABPersonViewController in story board, you do not need to write a single line of code. If you control dragged from the view controller that contains the button, then you should be calling performSegue to trigger the segue(you need to set the identifier for the segue in this case) that adds the ABPersonViewController to the navigation controller.

UIPopOverController + UITableView - Hide popover when cell is selected

In my Popover controller, i'm having a table view. On selection of a cell, I want to hide the pop over.
How can I achieve it.
In Header file of Root view controller:
#property (strong, nonatomic) UIStoryboardPopoverSegue* popSegue;
In the implementation file:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if( [[segue identifier] isEqualToString:#"popover"] )
{
NSLog(#"%#",[segue destinationViewController]);
self.popSegue = (UIStoryboardPopoverSegue*)segue;
[[segue destinationViewController] setDelegate:self];
}
}
When ever you want to hide the pop over:
if ([self.popSegue.popoverController isPopoverVisible])
{
[self.popSegue.popoverController dismissPopoverAnimated:YES];
}
In the table view, add a delegate and implement the delegate in root view controller. When the delegate method is called, use above code to dismiss the pop over.
Allow me to suggest a slightly different solution, which consists in passing the popover controller reference instead of the segue reference.
In the implementation file of the source view controller:
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue destinationViewController] isKindOfClass:[MyDestViewController class]]) {
MyDestViewController* viewController = (MyDestViewController*)[segue destinationViewController];
UIStoryboardPopoverSegue* popoverSegue = (UIStoryboardPopoverSegue*)segue;
[viewController setPopoverController:[popoverSegue popoverController]];
}
}
In the header file of the destination view controller:
#property (weak, nonatomic) UIPopoverController* popoverController;
In the implementation file of the destination view controller:
#synthesize popoverController;
Same file, whenever you want to dismiss the popover:
[popoverController dismissPopoverAnimated:YES];
The apple docs recommend the following:
Dismissing a popover programmatically requires a pointer to the popover controller. The only way to get such a pointer is to store it yourself, typically in the content view controller. This ensures that the content view controller is able to dismiss the popover in response to appropriate user actions.
http://developer.apple.com/library/ios/#documentation/WindowsViews/Conceptual/ViewControllerCatalog/Chapters/Popovers.html
in didSelectRowAtIndexPath try this code
[viewController.popoverController dismissPopoverAnimated:YES];

Resources