I have problem with calling methods from one UIViewController by another UIViewController.
Currently I have UIScroll view with two UIViewControllers.
I want to change something in second one and see results in first one.
I try to do this in this way:
Inside function of second UIViewController:
-(void)doSomething:(){
FirsOneViewController *firstVC = [FirsOneViewController alloc] init];
[firstVC changeUnits:0];
}
Function is called but I don't se any changes in first controller.
BR,
Paul
From your code I see you create a new instance of FirstViewController and so there is no reason why the current instance inside the scrollview would receive this message.
You need to send the changeUnits: message to the current FirstViewController, so you need a reference to it. To do this you may want to think about creating a protocol, so that you parent container (the scrollview) is notified by the SecondViewController and then notifies the FirstViewController. A simpler(and lazier) solution is make the SecondViewController have a strong reference to the FirstViewController (though this solution may bite you in the future).
As said in other answers you are creating a new instance of FirsOneViewController instead of referencing to the one you already have.
Here are three ways of doing what you are asking:
Delegation:
The FirstViewController should be the delegate of the SecondViewController (as the secondViewController is calling methods on the FirstViewController). You should tell the SecondViewController that the FirstViewController is its delegate in what ever class initialises the two viewControllers.
From what you have said so far this seems like your best option.
NSNotification:
This could be good option if you think more than one object will want to listen to the change in the SecondViewController. Just post an NSNotification in the SecondViewController and add an NSNotification listener in the FirstViewController
Singleton:
if there should only ever be one instance of the FirstViewController in existence then make it a singleton. By making a class initialiser method. so that you can create/get the current instance of the object from anywhere in your appellation.
Hope this helped.
Related
Say you have a ViewController that segues into a child ViewController. The child ViewController needs to be prepared with some values, typically set by the parent ViewController in the prepareForSegue() function.
Now say that some value in the child ViewController is updated and should be remembered for the next time it is called. What is the best way for the child ViewController to let the parent ViewController know of the updated value, so that it can be considered in subsequent calls to prepareForSegue()?
Please elaborate on the persistence/non-persistence of your solution and common/best practices.
You can create delegate from your child ViewController. Every time your values (you want to save) update, send it to parent ViewController.
See some example about delegate in here:
http://www.raywenderlich.com/115300/swift-2-tutorial-part-3-tuples-protocols-delegates-and-table-views
I know this has been asked, but I can't figure out how to make this work with my app -- I'm sure I'm doing it wrong.
I have two view controllers embedded inside a UITabBarViewContoller, FirstViewController and SecondViewController. SecondViewController is nothing more then a few UITextFields for managing a hostname and port that the app connects to.
FirstViewController contains most of the code (which I know isn't very MVC oriented). I'm trying to implement Delegation from SecondViewController back to FirstViewController (Passing Data between View Controllers) but it seems like my delegate methods aren't being called. Since this is based on storyboards, I'm not creating the instance of SecondViewController and I'm not sure how to set the Delegate. Is there a way to access the instance of SecondViewController so I can set the Delegate?
milesper thank you!
My solution (in swift)
let secondView = self.tabBarController.viewControllers[1] as SecondViewController
secondView.delegate = self
So I have a view controller FavoritesViewController and I have an instance of that view controller:
FavoritesViewController *FVC=[[FavoritesViewController alloc]init];
If I have two other view controllers, HomeViewController and SettingsViewController how do I have it so that I can push to that one particular instance "FVC" from both view controllers. I guess the real question is how/where can I initialize that instance "FVC" so that it is recognized by both view controllers and don't initialize it in HomeViewController or SettingsViewController.
Thanks
When you look at the MVC pattern, the object that you should really care about sharing is the model, not the controller. Your questions suggests to me that maybe the ViewController is also performing the responsibility of being the model.
If this is true, you might want to create another class (called Favorites, perhaps) and follow the suggestions in some of the previous answers to make it a singleton, if necessary. Doing it this way, rather than making the VC a singleton also has the benefit of working the same way whether you are using storyboards, xib, or code.
Maybe you have a good reason to need to share the VC itself, but I thought it would be worthwhile to question that premise.
If you want a single instance of your favorites view controller that is shared throughout your app, make it a singleton. Do a Google search on the singleton design pattern in iOS. The idea is that you would add a class method sharedFavoritesController that would always return the same instance, and use that.
The class method would look something like this:
+(FavoritesViewController *) sharedFavoritesVC;
{
static FavoritesViewController *_sharedFavoritesVC;
if (! _sharedFavoritesVC)
_sharedFavoritesVC = [[FavoritesViewController alloc] init;
return _sharedFavoritesVC;
}
Then #import the header for your FavoritesViewController class, and any time you need to invoke it, use:
[FavoritesViewController sharedFavoritesVC] to get a pointer to it.
Way 1 :
Declare
extern FavoritesViewController *FVC;
Way 2 :
If this is your rootViewController then in other viewcontrollers
FavoritesViewController *fvc=(FavoritesViewController*)appDelegateObj.rootViewController;
Way 3 :
use singleton
+(FavoritesViewController *) sharedInstance;
{
static FavoritesViewController *SVC;
if (! SVC)
SVC = [[FavoritesViewController alloc] init;
return SVC;
}
You could wrap a singleton pattern around that view controller.
Or, less elegant but more common, instantiate it in you AppDelegate and fetch it from there.
Be aware that the same instance of a view controller can only be once in the stack of view controllers. Plus - in principle - there is nothing wrong with having multiple instances of the same view controller class.
Edit in reply to your comment:
Not that I recommend that but this is how you would fetch a property sharedFavoritesViewController (which may refer to an instance of your FavoritesViewController) when your app delegate class is named MyAppDelegate:
FavoritesViewController localVar = [(MyAppDelegate)[[UIApplication sharedApplication] delegate] sharedFavoritesViewController];
I've been looking at view controllers for a few days now (searching xcode help, google and stack overflow), and I think I have some understanding of it, but not a lot.
I have some code, that I have trouble understanding.
So here I have the following code I found in the book I'm reading, and I'm not sure If I understand it correctly.
-(void)prepareForSegue(UIStoryboardsegue *)segue sender:(id)sender{
((ViewController2 *)segue.destinationViewController).delegate = self;
}
First, I have no idea why we typecast to our second view controller(viewController2) here.
I think I get the rest though, we take the method's segue parameter (which holds information about the view controllers involved in the segue), and we access the destinationViewController(meaning that we want to access the view controller that we are going to). We then set the delegate property of the destination view controller to self. I believe we set the delegate property to self, because we want to send messages to a delegate in the view controller we're going to.
Heres the last one I don't get:
In the header file:
#property (weak, nonatomic)id delegate;
In the implementation file: (the controllerVisisble property is a boolean, and is changed to YES when the user hits a button to perform a manual segue to the second view controller, which is this one)
-(void)viewWillDisappear:(BOOL)animated{
[super viewWillDisappear:animated];
((ViewController *)self.delegate).controllerrVisisble=NO;
}
Heres what I think this does: the viewWillDisappear method is called when a view is closing/removed.
I'm not quite sure about [super viewWillDisappear:animated], but I'm guessing that it gives an animation when the view disappears?However, I remove that line, and my dismissViewControllerAnimated method still gives an animation when the view controller is dismissed.
Here's the part that really confuses me. We need to access the first view controllers dateChooserVisible property somehow, to set it to NO, so we can access the second view controller again through our button. But, I don't understand why we have to typecast (viewController *), and type in self.delegate. Nor, do I understand why we created a property called delegate in the header file, to use here.
A lot of these questions are more generic than just within the context of view controllers.
[super methodName] calls the superclasses implementation of the method named methodName. In your case, Apple has written some code (that we don't have access to) in UIViewController's viewWillDisappear: method. ALWAYS call super when overriding a method from a superclass.
Note that viewWillDisappear: is just callback triggered whenever the view is set to disappear. My guess is that the super implementation of this method forwards this callback down to child view controllers, especially in the case of standard container classes like UINavigationController and UITabBarController.
The type casting really doesn't seem necessary, you can always call methods without compiler errors/warnings if the receiver is either type id or provides a declaration for the called method in its #interface.
As far as the delegates go, protocols and delegation are a major part of Objective-C, and widely used in Apple's APIs. This link might help you understand how they work; it helped me immensely.
I may go mad very soon.
This is the reason:
- I started up with Single View Application project with storyboards. Then I set the view controller class name in the storyboard for my viewController.
- Next step I created one pointer for this viewController in AppDelegate method ...didFinishLaunchingWithOpt... and filled it up by calling [myStoryboards instantiate...]. It works pretty good because I can call method like [vc1 setMyName] which does smthng like self.myName = #"Johnny";
- But here it comes. When I create IBAction method joined with button, this method doesn't know anything about "Johhny". And this is because I'm in another instance. When I check the address of "self" it is another one...
WhyWhyWhy??? Please help, how can I use still the same object - the one instantiated in AppDelegate by storyboards and the one from storyboards in "interface builder".
Thank you.
Oh my. I think I really underestamated it...
When we were talking about getting pointer of other viewControllers from storyboard...
I have initialViewController got by calling rootViewContr... And another one connected with segue (modal) where is UITableView. A get data on rootViewController and I want to show them on the other one in the list (UITableView). So I call segue (performSegueWithIdentifier), the other controller is shown but the list is clear. Because the method I call is working with tableView variable which is null :/ Because, again, I'm in another object. That is because I call that method storyboard instantiate... How can I get exactly the same viewController which I'm working in storyboard with. It is quite confusing for me :/
I read something about prepareForSegue and getting the pointer by destinationViewController but that is not what exactly I want. I need the pointer before I call segue method and the viewController is shown...
Thank you.
If you've set up your initial view controller properly in the storyboard, you don't need to assign it to the windows rootViewController property in -applicationDidFinishLaunchingWithOptions: as this is done for you automatically. It sounds like you're creating a second instance. To access the original instance setup by the storyboard simply do this in -applicationDidFinishLaunchingWithOptions:
InitialViewController *viewController = (InitialViewController *)self.window.rootViewController;
viewController.myName = #"Johnny";