Call method from PresentingViewController after segue pop over - ios

I have two view controllers in my project ViewController and SecondViewController and my ViewController has a button which performs a popover segue to SecondViewController then in my SecondViewController I have a button which I would like to use to a call a method from ViewController and I assumed it was possible using [self presentingViewController] but that pointer is set to nil so I'm not quite sure how to call a method in the first ViewController inside the SecondViewController after a popover segue.
This is the code for my ViewController.h
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController
- (IBAction)dosegue:(id)sender;
-(void)tobecalledfromseguepopover;
#end
ViewController.m
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
}
-(void)tobecalledfromseguepopover{
NSLog(#"Called from segue popover");
}
- (IBAction)dosegue:(id)sender {
[self performSegueWithIdentifier:#"segueforpopup" sender:self];
}
#end
SecondViewController.h
#import <UIKit/UIKit.h>
#import "ViewController.h"
#interface SecondViewController : UIViewController
- (IBAction)returntocaller:(id)sender;
#end
SecondViewController.m
#import "SecondViewController.h"
#interface SecondViewController()
#end
#implementation SecondViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
}
- (IBAction)returntocaller:(id)sender {
[self dismissViewControllerAnimated:YES completion:^{
ViewController* caller = (ViewController*)[self presentingViewController];
if(caller!=nil){
[caller tobecalledfromseguepopover];
}else{
NSLog(#"nil");
}
}];
}
#end
My UI
So any ideas on how I can call tobecalledfromseguepopover inside SecondViewController after the segue? Also is there a way for SecondViewCOntroller to know it's being called from a segue popover?

The usual thing is a delegate architecture. Give the popover a delegate property and set it to self in your prepareForSegue. Now the popover knows where to find the first view controller.
This is often combined with a protocol so that the popover knows the name of the method to be called without worrying about the class of the first view controller, but that part isn’t crucial, especially in Objective C.

Related

How to use delegate between two ViewController without StoryBoard?

I'd like to trigger a message from viewController to another viewController.
And I coded like below, but viewController didn't call delegate.
I want to call delegate without stroyboard. I just want to send a message to another viewController.
viewController2.h
#protocol ViewController2Delegate;
#interface ViewController2 : UIViewController
#property (nonatomic, weak) id<ViewController2Delegate> delegate;
#end
#protocol ViewController2Delegate <NSObject>
- (void)showSomethingByDelegate;
#end
viewController2.m
#import "ViewController2.h"
#interface ViewController2 ()
#end
#implementation ViewController2
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
}
- (IBAction)buttonPressed:(id)sender {
[self.delegate showSomethingByDelegate];
}
#end
viewController.m
#import "ViewController.h"
#import "ViewController2.h"
#interface ViewController ()
<ViewController2Delegate>
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
ViewController2 *vc2 = [[ViewController2 alloc] init];
vc2.delegate = self;
}
// Below method was not called by delegate.
- (void)showSomethingByDelegate {
NSLog(#"Button Was Pressed!!!");
}
#end
well let me show an example more simple.
File: firstVC.h
/* This define the protocol object,
you can write methods required or optional the diference is when
the protocol is used in a class, xcode show you a yellow warning with required methods
like UITableViewDelegate, UITextFieldDelegate... */
#protocol firstVCDelegate <NSObject>
#required
- (void)didMessageFromOtherViewController: (NSString *)messageStr;
#optional
- (void)didOtherMessageNotRequired: (NSString *)messageStr;
#end
/* This is the definition of first UIViewController */
#interface firstViewController : UIViewController
#end
/* This is the definition of second UIViewController object with
a property that is our protocol 'firstVCDelegate' */
#interface secondViewController : UIViewController
#property (nonatomic, weak) id <firstVCDelegate> firstVCDelegate;
- (void)executeDelegateProcess;
#end
File: firstVC.m
#import "firstVC.h"
#pragma mark - First UIViewController with delegate
#interface firstViewController() <firstVCDelegate>
#end
#implementation firstViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Creating the 'secondViewController' object with delegate on this class
secondViewController *svc = [secondViewController new];
// Assign the delegate class
[svc setFirstVCDelegate: self];
// Run the delegate logic
[svc executeDelegateProcess];
}
- (void)didMessageFromOtherViewController:(NSString *)messageStr
{
// Receiving the message from the instance of our protocol in the 'secondViewController' class
NSLog(#"MESSAGE #1: %#", messageStr);
}
- (void)didOtherMessageNotRequired:(NSString *)messageStr
{
// Receiving the message in optional method
NSLog(#"MESSAGE #2: %#", messageStr);
}
#end
#pragma mark - Second UIViewController
#implementation secondViewController
- (void)viewDidLoad
{
[super viewDidLoad];
}
- (void)setFirstVCDelegate:(id<firstVCDelegate>)firstVCDelegate
{
if (firstVCDelegate)
_firstVCDelegate = firstVCDelegate;
}
- (void)executeDelegateProcess
{
// This method is only for demo
// You can execute your delegate in the way you need to use
if (_firstVCDelegate) {
[_firstVCDelegate didMessageFromOtherViewController: #"Hello world, using the required method from secondViewController class"];
[_firstVCDelegate didOtherMessageNotRequired: #"Hello code using the optional method"];
}
}
#end
In your appDelegate.m in the method didFinishLaunchingWithOptions you can put this, and you need to #import "firstVC.h"
self.window = [[UIWindow alloc] initWithFrame: [[UIScreen mainScreen] bounds]];
self.window.autoresizesSubviews = YES;
[self.window makeKeyAndVisible];
[_window setRootViewController: [firstViewController new]];
Execute and see two logs messages, I hope I've helped :)
ViewController2 *vc2 = [[ViewController2 alloc] init];
This line of code is not doing what you think it is, this is creating a NEW instance of ViewController2 and storing it inside the variable vc2. At no point (based on your code) is this variable added to the navigation stack and displayed on screen.
Edit
Also as noticed by Holex, your vc2 variable will be removed from memory after the viewDidLoad is finished as you are not holding onto a reference of it. You would either need to create a property to hold onto it, or push it onto the navigation stack for the navigationController to hold onto it.
There are multiple ways to solve this issue:
Instead of creating a new viewController2, find a reference to the one already displayed on the screen (if it is on the screen).
If its not on the navigation stack, add vc2 to the navigation stack [self.navigationController pushViewController:vc2 animated:YES]; (assuming you have a navigation controller).
If not on the stack, and not intending to use a navigationController, present vc2 modally, such as [self presentViewController:vc2 animated:YES completion:nil];

How to setup a relationship between the presenting View Controller and the presented View Controller?

I'm still learning objective-c and having a difficult time dismissing presented VCs from presenting VCs.
I read that to achieve this, you establish delegates to send the right messages back to the presenting VC from the presented VC.
My storyboard looks like so:
The issue I have is if I click UIBUtton2, it doesn't go back to Main VC. In fact, it does nothing.
However, clicking on any cells from VC1 segue to VC2 and clicking on UIButton3 transition back to VC1 as achieved.
MainVC.h:
#import "VC1.h"
#interface MainVC : UIViewController <VC1Delegate>
....
MainVC.m:
- (void)didGoBackToMainVC
{
[self dismissViewControllerAnimated:YES completion:nil];
}
....
VC1 .h:
#import "VC2.h"
#protocol VC1Delegate <NSObject>
#required
- (void)didGoBackToMainVC;
#end
#interface VC1 : UIViewController <UITableViewDataSource, UITableViewDelegate,
VC2Delegate>
#property (weak, nonatomic) id <VC1Delegate> delegate;
- (IBAction)UIButton2:(UIButton *)sender;
VC1.m:
- (void)didGoBackToVC1
{
[self dismissViewControllerAnimated:YES completion:nil];
}
- (IBAction)UIButton2:(UIButton *)sender
{
[self.delegate didGoBackToMainVC];
}
VC2.h:
#protocol VC2Delegate <NSObject>
#required
- (void)didGoBackToVC1;
#end
#interface VC2 : UIViewController
#property (weak, nonatomic) id <VC2Delegate> delegate;
- (IBAction)UIButton3:(UIButton *)sender;
VC2.m:
- (IBAction)UIButton3:(UIButton *)sender
{
[self.delegate didGoBackToSponsors];
}
I'm sure I'm not understanding this relationship properly. Can someone tell me what I'm doing wrong?
Thanks
From what I understand in your comments above I saw that your Main VC shows VC1 Modally correctly.
So I guess you have this code in your VC1.m
- (IBAction)goToMainVC:(id)sender
{
[self dismissViewControllerAnimated:YES completion:nil];
}
Next make sure your Cell in VC1 has 'Triggered Seques' Selection type of 'Show'. And you probably had this code in your VC1.m
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"pushVC2"]) {
VC2 *vc2 = (VC2 *)segue.destinationViewController;
}
}
Next in your VC2.m you also should have this
- (IBAction)dismissVC2:(id)sender
{
[self dismissViewControllerAnimated:YES completion:nil];
}
If these are all you have, it should work like a charm. And no Delegates needed in this case. Hope this helps.

Passing Data between View Controllers Xcode 5

I'm new to iOS and Its developing.i have read Xcode old style passing data between view controllers.there i have seen lot of things going with xib files.please find below the code i have used to pass data in-between ViewControllers.but there in customelink(please find DetailViewController.m)there I'm getting Null value.please help me to get String value there.and kind enough to explain what are the mistakes I've done here.
EssentialInfoController.h
#import <UIKit/UIKit.h>
#import "DetailViewController.h"
#interface Essentialinfocontroller : UIViewController
#end
EssentialInfoController.m
#import "Essentialinfocontroller.h"
#interface Essentialinfocontroller ()
#end
#implementation Essentialinfocontroller
- (void)viewDidLoad
{
[super viewDidLoad];
DetailViewController * customelink= [DetailViewController alloc ];
customelink.link=#"https://www.facebook.com";
}
#end
DetailViewController.h
#import <UIKit/UIKit.h>
#interface DetailViewController : UIViewController
#property(weak,nonatomic)NSString * link;
#end
DetailViewController.m
#import "DetailViewController.h"
#interface DetailViewController ()
#property(nonatomic,weak)NSString *customelink;
#end
#implementation DetailViewController
#synthesize link;
#synthesize customelink;
- (void)viewDidLoad
{
[super viewDidLoad];
self.customelink=self.link;
NSLog(#"link--> %#",customelink);// here 2014-07-06 21:21:51.469 WADTourisum[880:60b] link--> (null)
}
#end
DetailViewController * customelink= [DetailViewController alloc ];
should be
DetailViewController * customelink= [[DetailViewController alloc ] init];
and
#property(weak,nonatomic)NSString * link;
should be
#property(strong,nonatomic)NSString * link;
and log it
NSLog(#"link--> %#",self.link);
you don't need this one
#property(nonatomic,weak)NSString *customelink;
if you use storyboard and segue then you have to implement
-(void)prepareForSegue method.
- (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];
// Pass any objects to the view controller here, like...
[vc setMyObjectHere:object];
}
}
assume that you got a button to move from essentialVC to detailVC, in you IBAction, call this method:
[self performSegueWithIdentifier:#"YOUR_SEGUE_NAME_HERE" sender:self];
this is just a brief answer. I suggest you read about UINavigationController first, it's much easier to use compared to segue, IMHO.

Button action not thrown

I am creating an iOS app. On a view controller there are several buttons.
One of them is the AButton, here you have my header file:
#import <UIKit/UIKit.h>
#interface FirstViewController : UIViewController
- (IBAction)Aaction:(id)sender;
#property (weak, nonatomic) IBOutlet UIButton *AButton;
#end
I want to open another view controller when AButton is tapped:
#import "FirstViewController.h"
#import "EntradasTableViewController.h"
#interface FirstViewController ()
#end
#implementation FirstViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)Aaction:(id)sender {
EntradasTableViewController *detailViewController =[self.storyboard instantiateViewControllerWithIdentifier:#"entradasViewController"];
detailViewController.categoriaDescription = #"A";
[self.navigationController pushViewController:detailViewController animated:YES];
}
#end
I have declared the StoryBoard identifier as follows:
But after tapping on the button nothing happens, no exception is thrown and the view controller detailViewController is not shown.
Any help is welcome.
NEW IMAGED ADDED:
Here is a screenshot where I am declaring the action for the button in the storyboard:
The problem is that your FirstViewController instance is not in a navigation interface. Therefore when your FirstViewController says self.navigationController, that's nil. Therefore this line:
[self.navigationController pushViewController:detailViewController animated:YES];
...involves sending a message to nil. In Objective-C, sending a message to nil does nothing. So that's why nothing happens.

iOS: Accessing the same instance of UIViewController that called the Segue

I have two view controllers. MainViewController pushes SignUp ViewController. Once SignUp View Controller dismisses, I need access to the same instance of MainViewController to update a UIButton.title.
.h MainView
//MainViewController.h
#import <UIKit/UIKit.h>
#interface MainViewController : UITableViewController
-(void)loggedIn;
#end
.m
#interface MainViewController ()
#end
-(void)loggedIn
{
NSLog (#"This is Logged in inside MainView.m");
self.logInOutButton.title = #"Logout";
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
UIViewController *destinationViewController = segue.destinationViewController;
Signup *signUp = [destinationViewController isKindOfClass:[SignUp class]] ? (Signup*)destinationViewController : nil;
signUp.mainViewController = self;
NSLog(#"Preapre For Segue %#", self);
}
.h SignUp
#import <UIKit/UIKit.h>
#import "MainViewController.h"
#interface SignUp : UIViewController
#property (strong, nonatomic) MainViewController *mainViewController;
#end
.m
#synthesize mainViewController;
- (void) loggedIn
{
NSLog(#" MainViewController %#", mainViewController);
[mainViewController loggedIn];
self.presentingViewController dismissViewControllerAnimated:YES completion:nil];
}
When I do NSLog I'm getting different values:
Preapre For Seg <STMainViewController: 0x9f7d600>
MainViewController (null)
Create a protocol / delegate. There are numerous resources on how to achieve this. In summary, you create the protocol on the destination viewController with the method you wish to run on the source and then you subscribe to that delegate from the source viewController.
Protocol Delegate
Dont forget to set the delegate from your prepareForSegue method
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
Signup *signUp = segue.destinationViewController;
signup.delegate = self;
NSLog(#"Preapre For Segue %#", self);
}

Resources