I have declared my method 'callWEBservice()' in ViewController1.m and i want to call in ViewController2.m . I have created object of ViewController1.m in ViewController2.m as:
ViewController1* mainVC = [[ViewController1 alloc] init];
Now i am trying to call that method but i am unable to do. Please help on this as I am new to iOS and I have searched some are saying to use delegates.
You need to define the method signature in your .h file -
- (void) callWebService;
and then in your .m file you define the method body:
- (void)callWebService
{
// Whatever you need to do to call the web service
}
Then in ViewController2.m you can #import "ViewController1.h"
Now you can call [mainVC callWebService];
BUT The code you have shown creates a new instance of ViewController1 - If you already have an instance of ViewController1, such as the main view in your app, then this probably isn't what you wanted - you may need to set a property in ViewController2 and store a reference to your ViewController1
e.g. in ViewController2.h
#import "ViewController1.h" // or use #class ViewController1 directive
#property (strong,nonatomic) ViewController1 *mainVC;
Then before in ViewController 1, before you present ViewController2 instance
vc2.mainVC=self;
Your invocation in ViewController2 then becomes
[self.mainVC callWebService];
At the risk of confusing you further, as a design note, it probably isn't best to have the callWebService method in a view controller. It might be more appropriate to create a singleton class for this purpose.
First of all, don't use view controllers for this purpose, create a new class to handle methods of the same kind, then use that one across your view controllers. IF you want the SAME class to be shared across your program, then create a singleton.
How to call method from one class in another (iOS)
However, if you still want to do the view controller to view controller thing, the reason its not working is because you are instantiating a new view controller, not the one you were already using.
You have to pass the reference of the first VC to the second VC. It depends on how you are presenting the second VC. If you are using the Interface Builder, then you need to use:
How to pass prepareForSegue: an object
If you are manually creating and presenting the VC, before presenting it let it know which is the first VC.
You can use delegates like this:
How do I set up a simple delegate to communicate between two view controllers?
STILL consider redesigning your usage of the view controllers.
EDIT:
2 options,
1) Singleton:
Follow this guide http://www.galloway.me.uk/tutorials/singleton-classes/
2) AppDelegate:
Instantiate an object of the class in the .m of the app delegate and assign it to a property in the .h of the App Delegate.
Then, retrieve this object.
This is an example of doing it with the motion manager from ios:
AppDelegate.h:
#property (strong,nonatomic) CMMotionManager *motionManager;
AppDelegate.m
_motionManager = [[CMMotionManager alloc] init];
ViewController1-2-etc
CMMotionManager *motionManager;
motionManager = ((AppDelegate*)[UIApplication sharedApplication].delegate).motionManager;
If you want to use methods from outside your class, you should declare them in your ViewController1.h file, not in the m, otherwise they are not visible (you could still call them using performSelector:withObject:afterDelay: but you should use the first solution)
Related
Please have a look at the screenshot of my project for better understanding
I have browsed a lot in stack overflow and other sites regarding writing custom delegates. But in my case the delegate is not getting called. As can be seen in the screenshot, the initial view controller has a button on click of which the tab bar gets called. From the first Tab bar screen, suppose I want to pass the data back to the initial view controller, how do I do? I can even use NSUserDefaults but I want to code the right way. So I came to know that delegates are best way to pass data back from one controller to the previous controller. But since I am using tab bars in between, the delegate is not getting called.. Kindly help,
Following is the code,
I want data to be passed from first tab to the initial controller.
TabScreenController.h:
#protocol TabScreenControllerDelegate <NSObject>
-(void)someFunction:(NSString*)someValue;
#end
#interface TabScreenController : UIViewController
#property (nonatomic, weak) id <TabScreenControllerDelegate> delegate;
#end
InitialViewController.h:
#interface InitialViewController : UIViewController<TabScreenControllerDelegate>
InitialViewController.m:
TabScreenController* controller = [[TabScreenController alloc]init];
[controller setDelegate:self];
//The delegate is not getting called
-(void)someFunction:(NSString *)someValue{
NSLog(#"%#", someValue);
}
The delegate is not getting called perhaps the TabScreenController in InitialViewController.m is a different instance than the one that gets created on clicking the tab.
Please help me regarding this.. How do I handle such scenarios. Let me know if I have not made myself clear..
Thank you
The error is that you are not setting the delegate the existing TabScreenController but instantiating a new TabScreenController and setting the delegate. When using TabBarController all the childViewControllers are already instantiated.
In your case you need to look for TabScreenController and then set its delegate.
NSArray* tabChildViewControllers = tabBarController.viewControllers;
for (UIViewController * childVC in tabChildViewControllers) {
if ([childVC isKindOfClass:[TabScreenController class]]) {
// set your the delegate
}
}
I have a button in mainviewcontroller, when that button is tapped I want to call a method on another view controller. Here below is an image showing my scenario, Green button click to call preview controller VC1 received method without navigation anything. I just need to call that method only!
Declare a method in .h file of VC1 and implement in .m file of VC1
Call that method from MainView Controller ,
Create a NSNotificationObserver in MainView Controller and implement it in .m file of MainView Controller ,
Now when method of VC1 is called and before it returns, fire a PostNotification from VC1 and pass the parameter which you want in MainView Controller.
#RobAu has given correct answer as you can use NSNotificationObserver and call from anywhere.
Other alternate which i have used is using protocol and is very simple.
Just declare a protocol in the child controller. while launching the view put the parent controller as delegate. now call the delegate method from where ever you want from child controller
Here is example which i used (In my case all the child controller was of same kind)
//ChildClass.h file of child class
#protocol updateIndex <NSObject>
-(void)updateMediaId:(NSString*)currentMediaId;
#end
#interface ChildClass : UIViewController
#property NSString *imageID;
#property id updateIndexDelegate;
#end
//ChildClass.m file for child class where you want to call the delegate method
(I called in viewDidAppear method)
-(void)viewDidAppear:(BOOL)animated{
[self.updateIndexDelegate updateMediaId:_imageID];
}
And in ParentClass.m file of parent class use the delegate to self like this
ChildClass *childObject = [[ChildClass alloc] init];
childObject.delegate = self;
and define the delegate method like this
-(void)updateMediaId:(NSString*)currentMediaId {
NSLog(#"%#",currentMediaId);
}
Enjoy coding
Edit: I've since learned that what I was doing is very, very poor design. Do not do what I did. Instead, consider reading up on how MVC works, and making proper classes. Do not substitute controllers for objects.
Not sure if I'm going about my architecture the proper way, but what I'm doing is declaring an app delegate in each of my view controllers, and then giving the app delegate it's own view controller delegate for each view controller.
I end up adding the same three lines to each view controller, and another view controller to the app delegate each time I create a new view controller. Is there an easier way to do this with inheritance (I.E. give all view controllers an appDelegate property, then assign it in some parent function).
Here's what I'm currently doing:
//AppDelegate.h
#interface AppDelegate
#property (strong, nonatomic) MyViewController* myViewDelegate;
#property (strong, nonatomic) MySecondViewController* mySecondViewDelegate;
#end
//MyViewController.m
#interface MyViewController ()
#property (strong,nonatomic) AppDelegate* appDelegate;
#end
#implementation MyViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.appDelegate = (AppDelegate*) [UIApplication sharedApplication].delegate;
self.appDelegate.myViewDelegate = self; //MySecondViewController would use:
//self.appDelegate.mySecondViewDelegate = self;
}
...
So two things:
I don't really see a way around declaring new view controllers in the app delegate without using a single root controller that gets assigned on segues, but is having multiple view controller delegates like I'm considered poor design in the first place?
I need a way for ViewDidLoad to call a parent ViewDidLoad to set the value of the app delegate property, as well as the declaration for that app delegate.
I am coding an app in Xcode and would like to know if it is possible to have an action called from a button in separate view controller.
For example, if there is a button on ViewController1 and the user presses the button, I would like an image to appear on ViewController2 and stay there even if the user navigates back to ViewController1 and then back to ViewController2 again. Can anyone help me please? Thank you.
UPDATED: I found a the answer to the question at the link below...
if my "button" is selected on view controller 1, then image should then display and stay on view controller 2
Yes, it is possible. If you declare the instance of ViewController2 within ViewController 1, then you can have full control over what's going on in ViewController2 at all times from ViewController1. For instance, in the .m, have
#implementation ViewController1
#synthesize viewController2
- (void) viewDidLoad
{
viewController2 = [[UIViewControllerClass alloc] init];
}
and in the .h, have
#interface ViewController1
#property (nonatomic, strong) UIViewControllerClass *viewController2;
This will make sure that ARC does not scrap your second ViewController before you're done with it, which in this case is when you terminate the program.
Then, you can simply call methods that belong to ViewController2 from ViewController1 like you would with any other class.
[viewController2 doSomethingWithThisData: stringData];
A few considerations not yet mentioned...
Depending on how you transition between viewControllers & where the shared data (images etc) are set, one option is for VC2 to have a public #property to set the image.
VC2.h
#IBOutlet (nonatomic, weak) UIImageView *imageFromVC1;
VC1 should import the VC2 header so it can create & hold an instance of VC2 and set the image.
You'd need to keep track of VC2's state in VC1, as a #property of VC1.
VC1.m
#import VC2.h
#interface VC1()
#property (nonatomic, strong) VC2 *viewController2;
#end
#implementation
...
Note that this does not need to go in the .h for VC1 - unless other classes need to know about it, this should be a private property in a class extension of .m & not exposed in the header. You don't need to use #synthesize anymore either - that's automatic if you're using XCode 4.4 or later.
The issue at this point is that VC2 shouldn't exist until it's needed (it's a waste of limited memory). You could create it right away in -viewDidLoad in VC1, but then it's just sitting there sucking up resources.
Better option is 'lazy instantiation' where you only create a VC2 instance when you transition to showing VC2 for the first time. Also set the #property in VC1 at this point.
-(void)someMethodToShowVC2OrStoryboardPrepareForSegue {
if (self.viewController2 == nil)
{
self.viewController2 = [[VC2 alloc] init];
}
//handle transition & set up VC2.
}
You could also ask VC2 to be sure it has the public method that allows you can set the image. If it doesn't, it will crash. By writing & importing the VC2 header obviously you should know that the method exists - this is just a defensive practice and alternative to sending the message to VC2 directly:
if ([self.viewController2 respondsToSelector:#selector(setImageFromVC1)])
{
UIImage *myImage = [UIImage imageNamed:#"myImageName"];
[self.viewController2 setImageFromVC1:myImage];
}
Here "setImageFromVC1" is the name of the setter method that is automatically generated when you use an #property. Change this if you use another name.
Alternative is to use dot notation: self.viewController2.imageFromVC1 = myImage;
Note that this "Key-Value Observing" approach to setting properties on other objects isn't the only, or necessarily the best, approach to doing this - but it works.
I have following code:
LoginViewController *lvc = [[LoginViewController alloc] initWithNibName:#"LoginViewController" bundle:nil];
[self presentModalViewController:lvc animated:false];
[lvc release];
That is called from my MainViewController.
Now, when the LoginViewController will be dismissed (of course this only happens when the login is correct) I must call a method in my MainViewController to load the initial data for my app.
I read a lot about delegate and tried it, but don't get it to work.
Could someone help me please?
(if possible, please with a few lines of code)
Any help is welcome!
I read a lot about delegate and tried it, but don't get it to work.
What have you tried really? Your LoginViewController must define a simple delegate protocol, and your MainViewController must conform to it.
All you need to do is add something like this in LoginViewController.h above #interface:
#protocol LoginViewControllerDelegate
- (void)loginViewControllerDidFinish;
#end
Which declares a protocol with one method. Then add this between #interface and #end:
#property (nonatomic, assign) id <LoginViewControllerDelegate> delegate;
Which means your login view controller will have a property called delegate which will point to an instance of any class (that's what id means) that conforms to it's delegate protocol (the thing between < and >). Don't forget to #synthesize delegate; inside .m file.
Now what you need to do is inside MainViewController.h add to #interface line like this:
#interface MainViewController : UIViewController <LoginViewControllerDelegate>
Which tells the compiler your MainViewController class conforms to this LoginViewControllerDelegate delegate protocol. Now implement the - (void)loginViewControllerDidFinish; method inside MainViewController.m and before presenting the login view controller modally set it's delegate to self (login.delegate = self;). When you are done inside your login view controller, before you dismiss it, call the delegate method on your delegate:
[self.delegate loginViewControllerDidFinish];
And that's it. Any more questions?
Try this:
1) when pushing login view, set some flag in MainViewController
2) in method viewWillAppear in MainViewController check that flag from 1). If it is set then load the initial data and unset flag. Otherwise push LoginView.
You've got an UIApplicationDelegate, and it should have an instance variable that points to the MainViewController. Expose this instance variable via a property, say mainViewController (on your UIApplicationDelegate), and then you can access it like this:
[(MyUIApplicationDelegate *)[[UIApplication sharedApplication] delegate] mainViewController]