ios10 prepareForSegue popoverPresentationController ObjC - objective-c

I have UITableViewController in UINavigationController which I want to show in popover view and populate the fields in viewController.
Storyboard looks like the pic bellow. Left VC calls editIdeaSeque on navigation button press.
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"editIdeaSegue"]) {
UINavigationController *nvc = segue.destinationViewController;
if (!isIpad) {
EditIdeaTVC* edi = (EditIdeaTVC*)[nvc.viewControllers objectAtIndex:0];
if (edi != nil)
edi.editIdea = sender;
}
else {
UINavigationController* nc = (UINavigationController*)[[segue.destinationViewController popoverPresentationController] presentedViewController];
EditIdeaTVC* edi = (EditIdeaTVC*)[nc.viewControllers objectAtIndex:0];
if (edi != nil)
edi.editIdea = sender;
}
}
}
My prepare for segue works for iphone which is similar storyboard layout. Ipad part crashes cause edi is some garbage pointer.
-[EditIssueTVC setEditIdea:]: unrecognized selector sent to instance 0x157d6c7a0
I was expecting that presentedViewController will be UINavigationController ...

UINavigationController* nc = (UINavigationController*)[[segue.destinationViewController popoverPresentationController] presentedViewController];
You're over-thinking this. The navigation controller is the destination view controller. The situation is identical to your earlier code:
UINavigationController *nvc = segue.destinationViewController;
There is nothing about the popover situation that would change what view controller is at the far end of the destination arrow.

Related

Performwithsegue and programatically switching views - Objective-C

I am having a problem, I want to change to another viewcontroller when a timer expires and this works with this code:
- (IBAction)Akkoord:(id)sender {
UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
UIViewController *vc = [mainStoryboard instantiateViewControllerWithIdentifier:#"Innameformulier"];
[self presentViewController:vc animated:YES completion:nil];
[self performseguewithidentifier:#"nextcontroller"]
}
But when I use this, my variables in my prepareforsegue method are not passing. How can I do this? I already tried [self performseguewithidentifier] but this is not working.
my preparforsegue code is:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
Innameformulier *IForm = [segue destinationViewController];
IForm.SignatureTransport = _drawImage.image;
IForm.KlantnaamInname = _Klantnaamtransport;
}
How can I call this function to happen on the timer?
In Interface Builder, select the View Controller from which you want to fire a segue, CTRL-drag from it to the destination View Controller and create a segue.
Select the segue, open the Attributes Inspector and create an Identifier for it.
Go back to your View Controller Class that fires the segue and if you don't already have it commented, add the method prepareForSegue:
In your prepareForSegue: method you should have something like the following:
- (void)prepareForSegue:(UIStoryboardSegue *)segue {
if ([segue.identifier isEqualToString:#"XXXX"]) {
DestinationVC *dVC = segue.destinationViewController;
dVC.attribute1 = self.anAttribute;
dVC.attribute2 = self.anotherAttribute;
}
}
And now you can fire the segue by calling [self performSegueWithIdentifier:#"XXXX"].
Note: you can also fire an action segue from an UIControl subclass like UIButton
OK, what you are doing here is bypassing the segue completely. You need to do something like this...
- (IBAction)Akkoord:(id)sender {
[self performseguewithidentifier:#"nextcontroller"]
}
This is all you need to do. The segue will then create the nextController for you and then the code inside prepareForSegue will pass the variables across.
If you want it on a timer then you just need to set up a timer and when it expires you can run...
[self performseguewithidentifier:#"nextcontroller"]
As long as you have a segue with this identifier then it will work anywhere. Ever after a timer.

How to show the data of a textfield to the label of a tableview cell?

I am new to iOS developing. I am building a project where I want to show the text of a textfield of a view controller to the label of a table view cell of another viewcontroller. Can anyone tell me just the logic how to do that?
Since you haven't posted any code, I will try to explain it to you.
You will have to create event for button, and there you can do something like [self performSegueWithIdentifier:#"yourSegue" sender:self];
Next thing is to create property in your new ViewController that will accept your value.
After that, in your prepareForSegue you can do NSString *text = [self.textField text];, get your new VC from segue.destinationViewController; and assign your value there.
So, in the end you will have :
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if(segue.identifier isEqualToString:#"yourSegue"])
{
YourViewController *vc = segue.destinationViewController;
vc.accpetValue = [self.yourTextField text];
}
}
and in your action for button:
- (IBAction)yourButton_pressed:(id)sender
{
[self performSegueWithIdentifier:#"yourSegue" sender:self];
}
If you have tableViewController there, and you want to assign this value to the cell on the same screen, on button you can obtain the value with same way as above, and in you cellAtIndexPath you can do the following:
if(self.yourTextBox && [self.yourTextBox text] && ![[self.yourTextBox text] isEqualToString:#""])
{
cell.textLabel.text = [self.yourTextBox text];
}
else
{
//something else
}
And on your button event you can do
[self.tableView reloadData];
Hope it helps.
If the view controller with the cell is open from the view controller with the textfield, is quite easy.
You can create a property NSString in the second view controller .h and then you can call it when you open this from the first.
SecondViewController * cotroller = [[SecondViewController alloc]init];
controller.string = [textField text];
[self presentViewController:controller animated:YES completion:^{
}]

Present a Different View Controller After Dismissing a Modal View Controller

I present a modal view controller for various UI settings in an iOS app. One of those settings allows the user to select a different main view. When they hit "Done" I want to dismiss the modal view and have the newly-selected view controller appear, without a momentary delay where the old view controller segues to the new view controller. How could this be implemented?
Update:
Here is a method I successfully implemented using Eugene's technique, but without the app delegate. Instead, this implementation is specific to my scenario where a view controller in a navigation stack presents the modal view controller in a Utility app.
- (void)swapFrontSideViewController;
{
UINavigationController *navigationVC = (UINavigationController *)[self presentingViewController];
NSMutableArray *viewControllers = [NSMutableArray arrayWithArray:navigationVC.viewControllers];
UIViewControllerSubclass *selectedViewController = nil;
if ([self.selectedFrontSide isEqualToString:FRONT_SIDE_NAME1]) {
selectedViewController = [self.storyboard instantiateViewControllerWithIdentifier:FRONT_SIDE_NAME1];
} else if ([self.selectedFrontSide isEqualToString:FRONT_SIDE_NAME2]) {
selectedViewController = [self.storyboard instantiateViewControllerWithIdentifier:FRONT_SIDE_NAME2];
}
if (selectedViewController) {
[viewControllers replaceObjectAtIndex:viewControllers.count -1 withObject:selectedViewController];
[navigationVC setViewControllers:viewControllers];
self.delegate = selectedViewController;
} else {
NSLog(#"Error: Undefined Front Side Selected.");
}
}
- (IBAction)doDismiss:(id)sender {
AppDelegate *appDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate; // Get the app delegate
NSMutableArray *viewControllers = [NSMutableArray arrayWithArray:appDelegate.navigationController.viewControllers]; // fetch its navigationController viewControllers stack
UIViewController *replacementController; //initialize replacement controller
[viewControllers replaceObjectAtIndex:viewControllers.count -1 withObject:replacementController]; // replace the top view controller in stack with the replacement one
[appDelegate.navigationController setViewControllers:viewControllers]; //change the stack
[self dismissModalViewControllerAnimated:YES];
}

How do I use a property in -prepareForSegue?

Here is my code, posted in view1:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
// Make sure your segue name in storyboard is the same as this line
if ([segue.identifier isEqualToString:#"toLevels"])
{
levelViewController *vc = [segue destinationViewController];
vc.currentEnchantmentSelected = self.title;
}
}
This doesn't send the value of "self.title" to the variable in "levelViewController". Why is this? It sends it if I use a string.
Edit (levelViewController):
#synthesize enchantment = _enchantment;
- (enchantmentViewController *)enchantment
{
if (!_enchantment){
_enchantment = [[enchantmentViewController alloc] init];
}
return _enchantment;
}
the #property enchantment is declared in the header.
So from the chat, the issue was that you were setting this property in didSelectRowAtIndexPath:, which is actually called after prepareForSegue:sender: with storyboards. (when the segue is attached to a cell in a table)
So the solution is just to do that work directly in prepareForSegue:sender: instead. The sender will be the cell that was tapped. And if you need the indexPath for that cell you can use:
[self.tableView indexPathForSelectedRow]
Good luck with the app.

How to set the delegate with a storyboard

I've been debating with this for a while now, hope you can help me.
I've been creating an app using storyboards mostly, I have a point where I popup a modal box to add a new record, popup works fine, the problem is dismissing it.
I've followed Apple's instructions on how to properly close modal boxes using delegates, and that works fine, except I need to add a navigation controller to my modal box, because the add process requires two steps (here fullscreen):
The problem lies in setting the delegate, so here are my two questions:
1- In my root view class (My Tab) is a delegate of the Add class (the modal), everything is set up right except this:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"showAdd"]) {
[[segue destinationViewController] setDelegate:self];
}
}
The problem lies in that [segue destinationViewController] is returning the navigationcontroller and not the AddDrinkViewController class (see the storyboard). How do I get around this? If I remove the navigation controller altogether, the code works fine setting the appropriate delegate.
2- Is there any way to set the delegate by dragging the outlets in the storyboard?
Thanks!
You're right, the destinationViewController will be a UINavigationController in this case. I wrote a category to handle this common situation:
// category .h file
#interface UIStoryboardSegue (NavControllerExtensions)
// Gets destinationViewCotroller. But if that controller
// is a NavigationController, returns the nav controller's
// top level view controller instead.
#property (readonly) id topLevelDestinationViewController;
#end
// category .m file
#implementation UIStoryboardSegue (NavControllerExtensions)
- (id)topLevelDestinationViewController
{
id dest = self.destinationViewController;
if ([dest isKindOfClass:[UINavigationController class]]) {
UINavigationController* nav = dest;
dest = nav.topViewController;
}
return dest;
}
#end
So now you can just do this in any of your prepareForSegue methods, and not need to worry about whether there even exists a NavigationController:
[[segue topLevelDestinationViewController] setDelegate:self]
// another example:
MyViewController *vc = segue.topLevelDestinationViewController;
vc.delegate = self; // etc.
To answer your second question, I couldn't find a way to set the delegate within IB.
I found a shorter way in my case (same as yours):
AddDrinkViewController *controller=[[[segue destinationViewController]viewControllers]objectAtIndex:0];
Basically you need to create an
Instance of UINavigationController and assign destinationViewController to it
and grab its topView controller
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"showAdd"]) {
UINavigationController *navigationController = segue.destinationViewController;
AddDrinkViewController *addDrinkcontroller = (AddDrinkViewController *)navigationController.topViewController;
addDrinkcontroller.delegate = self;
}
}