I'm trying to access some things from another viewcontroller (iOS).
I have my ViewController.h:
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController <UITextFieldDelegate> {
...
}
#end
ViewController.m:
#import "ViewController.h"
#import "ViewController2.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad
{
ViewController2.someVar = #"cakes"; // this is where I'm trying to set something in vc2
}
ViewController2.h:
#import <UIKit/UIKit.h>
#interface ViewController2 : UIViewController <UITableViewDataSource, UITableViewDelegate, UISearchDisplayDelegate>
{
...
}
#property (nonatomic, copy) NSString *someVar;
#end
ViewController2.m:
#import "ViewController2.h"
#interface ViewController2 ()
#end
#implementation ViewController2
#synthesize someVar;
etc.
But at the line where I try to access this var, it gives me the following error:
Property 'someVar' not found on object of type 'ViewController2'.
In what way would I achieve accessing this other view controller?
You have to create a ViewControlle2 object in your Viewcontroller.m.
ViewController2 *myVC2 = [[ViewController2 alloc] initWithNibName:#"ViewController2" bundle:nil];
myVC2.someVar = #"cakes";
Another way to do this is by using delegates. If you created ViewController1 in AppDelegate, you should also create ViewController2 in AppDelegate, or where ever you create your ViewControllers. Then you ViewController1 would send a message to AppDelegate to get the data from ViewController2 and vice versa. This makes ViewController1 and ViewController2 no longer dependent on each other.
So in AppDelegate.h we'd have something like this
#interface AppDelegate : NSObject <MyViewControllerDelegate>
#property (nonatomic) ViewController1 *viewController1;
#property (nonatomic) ViewController2 *viewController2;
#end
Then in both view controllers you can add this line in the .h
#property (nonatomic) id<MyViewControllerDelegate> delegate;
This just gives us a variable to use to refer to the delegate from within the ViewController's .m
You also need to create the MyViewControllerDelegate protocol, so in a file called MyViewControllerDelegate.h
#protocol MyViewControllerDelegate
- (ViewController1 *) viewController1;
- (ViewControlelr2 *) viewController2;
#end
Then when you create the ViewControllers in AppDelegate.m, you should also set AppDelegate as the ViewController's delegate.
self.viewController1 = [[ViewController1 alloc] init];
self.viewController1.delegate = self;
self.viewController2 = [[ViewController2 alloc] init];
self.viewController2.delegate = self;
So with all of this delegate set up done, you should be able to access viewController2.someVar from viewController1 through the delegate by using:
self.delegate.viewController2.someVar = #"Cakes";
Hope this isn't too long winded.
Related
I have the delegate method I implement to pass data from FirstViewController to SecondViewController.
First, I created a text Field and Button in FirstViewController. Second, I created a label to display the data in SecondViewController.
How it should work:
The user will press the button in FirstViewController and it will pass the data to the secondViewController.In addition,the user will be using a UISwipeGestureRecognizer to navigate to the second view controller, so there's no need to use the button to go to the second view controller.
How I test the application
1- I run the application. --> 2- I type "Hello" in Text field --> 3- I press the button --> 4- I swipe to the second view controller to see the data --> 5- I don't see any data in the label ??
First i created the delegate protocol
FirstViewController.h
#class FirstViewController;
#protocol FirstControllerDelegate
-(void) updateLabel:(NSString*)string
#end
#property (weak, nonatomic) id<FirstViewControllerDelegate>delegate;
#property (weak, nonatomic) IBOutlet UITextField *TextField;
- (IBAction)button:(id)sender;
FirstViewController.m
#interface FirstViewController. ()
#end
#implementation ViewController1
#synthesize delegate;
#synthesize TextField;
-(void)viewDidLoad{
[super viewDidLoad];
}
- (IBAction)Button:(id)sender {
ViewController2 *vc2 = [[ViewController2 alloc] init];
vc2.stringfromTextfield1 = self.TextField.text;
}
SecondViewController.h
#import "SecondViewController.h"
#import "FirstViewController.h"
#interface SecondViewController : UITableViewController<FirstControllerDelegate>
#end
#property (weak, nonatomic) IBOutlet UILabel *Label;
#property (strong, nonatomic) NSString *stringfromTextfield1;
SecondViewController.m
#interface SecondViewController. ()
#end
#implementation SecondViewController
-(void)viewDidLoad{
[super viewDidLoad];
self.label.text = self.stringfromTextfield1;
}
I appreciate your time and effort to help me out
You can use Singleton class for this, or you can use extern NSString for move the string value one to second View Controller.
in first view controller.
extern NSString *MyStr;
in the #interface define it.
#interface{
NSString *MyStr;
}
In the #Implementation assign the value what you want.
and the second view controller just #import the first view and use,
MyStr As a variable and its having the value also from first view controller.
This thing worked for me.
Or simply add an AppDelegate property to store the variable in both ViewControllers:
AppDelegate *appDel=[[UIApplication sharedApplication] delegate];
appDel.variable=#"text";
You can save data in App delegate and access it across view controllers in your application.You have to create a shared instance of app delegate.
AppDelegate *appDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
like this
Suppose you declare a NSString object *strthen you can access it in any view controller by appDelegate.str
I'm using a Split View Controller for an iPad app. I'm trying to send a label change to the detailReceiving Controller from the rootSending Controll when a button is pushed. I've read through tutorials on protocols and came up with the code below. When I click the button on rootSending, nothing happens to the label on detailReceiving. Do I have to do something else with a splitViewContoller so that the label will update? Shouldn't detailReceiving change the label when it receives the message?
rootSending.h
#import <UIKit/UIKit.h>
#protocol TestDelegate <NSObject>
-(void)tester:(NSString*)testString;
#end
#interface rootSending : UIViewController
#property (nonatomic, assign) id <TestDelegate> delegate;
#end
rootSending.m
#import "rootSending.h"
#implementation rootSending
#synthesize delegate;
-(void)viewDidLoad{
}
-(IBAction)buttonPressed:(id)sender{
[delegate tester:#"button pressed"];
}
#end
detailReceiving.m
#import "detailReceiving.h"
#import "rootSending.h"
#interface detailReceiving ()<TestDelegate>{
IBOutlet UILabel *label2;
}
#end
#implementation detailReceiving
-(void)viewDidLoad{
rootSending *obj = [rootSending alloc];
obj.delegate = self ;
}
-(void)tester:(NSString *)testString{
label2.text = testString;
}
#end
First of all, never ever have an alloc without an init! But in this case, even if you did use alloc/init, it still wouldn't work because that just creates a new instance of rootSending, not the one that you have in your split view. You need to get a reference to the one you have, which you can get from the split view controller,
-(void)viewDidLoad{
rootSending *obj = (rootSending *)self.splitViewController.viewControllers.firstObject;
obj.delegate = self;
}
After Edit:
If your mate controller is embedded in a navigation controller, then you need to get the navigation controller's topViewController to get your reference.
-(void)viewDidLoad{
UINavigationController *nav = (UINavigationController *)self.splitViewController.viewControllers.firstObject;
xmlListOfItems *obj = (xmlListOfItems *)nav.topViewController;
obj.delegate = self;
}
I know there are tons of questions out there about passing messages between different view controllers. I've checked them all but I can't get it working.
I've followed this tutorial: http://www.youtube.com/watch?v=XZWT0IV8FrI replacing the storyboard with a navigation controller but I run across the following issue over and over again: 'Cannot find protocol declaration for...'
Here is the code:
FirstViewController.h
#import "SecondViewController.h"
#interface FirstViewController : UIViewController <SecondViewControllerDelegate>{
//In this line above is where I get the error 'Cannot find protocol declaration for SecondViewControllerDelegate'
IBOutlet UITextField *userNameTextField;
}
#property (nonatomic, strong) UITextField *userNameTextField;
-(IBAction)goNext:(id)sender;
#end
FirstViewController.m
#import "FirstViewController.h"
#interface FirstViewController ()
#end
#implementation FirstViewController
#synthesize userNameTextField;
-(void)goNext:(id)sender{
SecondViewController *secondVC = [[SecondViewController alloc]init];
secondVC.delegate = self;
[self.navigationController pushViewController:secondVC animated:YES];
}
-(void)done:(NSString*)name{
NSLog(#"BACK in firstVC");
userNameTextField.text = name;
}
#end
SecondViewController.h
#import "FirstViewController.h"
#protocol SecondViewControllerDelegate <NSObject>
-(void)done:(NSString*)someText;
#end
#interface SecondViewController : UIViewController{
IBOutlet UITextField *someText;
IBOutlet UIButton *returnButton;
id delegate;
}
#property (assign, nonatomic) id <SecondViewControllerDelegate> delegate;
#property (strong, nonatomic) UITextField *someText;
-(IBAction)goBack:(id)sender;
#end
SecondViewController.m
#import "SecondViewController.h"
#interface SecondViewController ()
#end
#implementation SecondViewController
#synthesize someText;
#synthesize delegate = _delegate;
-(void)goBack:(id)sender{
[self.delegate done:someText.text];
FirstViewController *firstVC = [[FirstViewController alloc]init];
[self.navigationController pushViewController:firstVC animated:YES];
}
#end
In your SecondViewController goBack implementation you are creating a new FirstViewController rather than popping your navigation controller, code should read...
-(void)goBack:(id)sender{
[self.delegate done:someText.text];
[self.navigationController popViewControllerAnimated:YES];
}
And also in your SecondViewController.h remover this #import "FirstViewController.h" as it is no longer needed and could be confusing the compiler
Your protocol name is EYSSecondViewControllerDelegate:
#protocol EYSSecondViewControllerDelegate <NSObject>
but you call it SecondViewControllerDelegate in two places:
#interface EYSFirstViewController : UIViewController <SecondViewControllerDelegate>{...
#property (assign, nonatomic) id <SecondViewControllerDelegate> delegate;...
Make sure that the name match and it should works fine.
In SecondViewController.h
remove line id delegate;
In SecondViewController.m
Update code -> [delegate done:someText.text];
'self.' remove
Try it
In UINavigationController this is child controller
.h
#protocol childProtocol <NSObject>
-(void)childMethod:(NSArray*)params;
#end
#property (strong, nonatomic) id<childProtocol>childDelegate;
#property (weak, nonatomic) parentVC *pVC;
.m
if([self.childDelegate respondsToSelector:#selector(childMethod:)]) {
[self.childDelegate performSelector:#selector(childMethod:) withObject:self.arry];
}
This is my parent controller
.m
-(void)childMethod:(NSArray *)params {
// some work
}
...
childVC *cVC = [[childVC alloc]init];
cVC.pVC = self;
But childMethod: is not getting called so I searched on internet and got this post
UINavigationControllers: How to pass value to higher (parent?) controller in stack?
I tried to create a weak reference but dont know how to use to make delegate pass data from child to parent?
Try this. Check the sample project attached
ParentViewController.h
#import <UIKit/UIKit.h>
#interface ParentViewController : UIViewController
- (void)passData:(NSString *)strText;
#end
ParentViewController.m
- (IBAction)btnGoToSecondView:(id)sender {
ChildViewController *secondVC = [[ChildViewController alloc] initWithNibName:#"ChildViewController" bundle:nil];
secondVC.delegate = self;
[self presentViewController:secondVC animated:YES completion:nil];
}
- (void)passData:(NSString *)strText {
NSLog(#"Data Passed = %#",strText);
}
ChildViewController.h
#import <UIKit/UIKit.h>
#import "ParentViewController.h"
#class ParentViewController;
#interface ChildViewController : UIViewController
#property(nonatomic, assign) ParentViewController *delegate;
#end
ChildViewController.m
- (IBAction)btnPassDataBack:(id)sender {
if([self.delegate respondsToSelector:#selector(passData:)]) {
[self.delegate passData:#"Hello"];
}
[self dismissViewControllerAnimated:YES completion:nil];
}
Sample Project
This is child controller.h
#protocol childProtocol <NSObject>
-(void)childMethod:(NSArray*)params;
#end
#property (strong, nonatomic) id<childProtocol>childDelegate;
#property (weak, nonatomic) parentVC *pVC;
.m
if([self.childDelegate respondsToSelector:#selector(childMethod:)]) {
[self.childDelegate performSelector:#selector(childMethod:) withObject:self.arry];
}
This is my parent controller.h
#import <UIKit/UIKit.h>
#import "ChildController.h"
#interface perentController : UIViewController < childProtocol >
.m
- (void)childMethod:(NSArray *)params {
// some work
}
EDITED :
And Dont Forget to add childViewOBJ.childDelegate = self; at the time of create ChildViewController's object. such like,
childVC *cVC = [[childVC alloc]init];
cVC.childDelegate = self;
cVC.pVC = self;
[self presentModalViewController:cVC animated:YES];
For More information about How to create/use of Protocol.
First of all, you are not checking for the same selector as you declared in your protocol declaration so it won't respond to that. You declared the method childMethod: whereas you are checking if your childDelegate responds to myMethod: selector which does not so it won't go into the if condition.
Also the parent view controller is missing the implementation the method childMethod: in its .m. Implement that in your parent view controller or it will crash because of not finding the exact selector definition.
Since you are using a UINavigationController, the parent view controller won't be lost till the child view controller exist so the childDelegate property must not be strong unless you intend to hold onto your delegate in child view controller for some reason.
So I have 3 views as follows: viewController >> viewController2 >> viewController3.
In viewController3 I have created a Delegate Protocol. The protocol method is a simple method that prints out an NSLog.
When I call the delegates from ViewController3, only its parent (viewController2 ) responds not the (first) viewController. There are no errors.I think problem has got something to do with [v2 setDelegate:self]; in the viewController.m file.
Nevertheless,[self.v3 setDelegate:self]; works fine in ViewController2.m file.
Why does the (first) viewController delegate not respond ? Do delegates only work with its immediate child ??
> **ViewController.h**
#import <UIKit/UIKit.h>
#import "ViewController2.h"
#import "ViewController2.h"
#interface ViewController : UIViewController <PassData>{
ViewController2 *v2;
}
#property (strong, nonatomic) ViewController2 *v2;
> Blockquote
- (IBAction)button:(id)sender;
#end
> **ViewController.M**
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
#synthesize v2;
- (IBAction)button:(id)sender {
v2 = [[ViewController2 alloc]initWithNibName:#"ViewController2" bundle:nil];
[v2 setDelegate:self];
[self.view addSubview:v2.view];
}
-(void)print: (BOOL)success;{
if (success == YES) {
NSLog(#"ViewController called");
}
}
#end
> > ViewController2.h
#import <UIKit/UIKit.h>
#import "ViewController3.h"
#interface ViewController2 : UIViewController <PassData> {
ViewController3 *v3;
}
#property (strong, nonatomic)ViewController3 *v3;
#property (retain) id delegate;
- (IBAction)button:(id)sender;
#end
ViewController2.m
#import "ViewController2.h"
#interface ViewController2 ()
#end
#implementation ViewController2
#synthesize v3,delegate;
- (IBAction)button:(id)sender {
v3 = [[ViewController3 alloc]initWithNibName:#"ViewController3" bundle:nil];
[self.v3 setDelegate:self];
[self.view addSubview:v3.view];
}
-(void)print: (BOOL)success;{
if (success == YES) {
NSLog(#"ViewController2 called");
}
}
#end
> ViewController3.h
#import <UIKit/UIKit.h>
#protocol PassData <NSObject>
#required
-(void)print:(BOOL)success;
#end
#interface ViewController3 : UIViewController {
id<PassData> delegate;
}
#property (retain) id delegate;
- (IBAction)callButton:(id)sender;
#end
ViewController3.m
#import "ViewController3.h"
#interface ViewController3 ()
#end
#implementation ViewController3
#synthesize delegate;
- (IBAction)callButton:(id)sender {
// call all delegates
[[self delegate]print:YES];
}
#end
v2 doesn't have a method "print", that's a protocol method of v3 -- you can't chain delegate messages like this. If you want multiple controllers to respond to something in another controller, then you should use an NSNotification -- any number of objects can register to receive a notification.