Delegate doesn't get called from another viewcontroller, tried everything - iphone

I have 2 viewcontrollers, with a segue between them. My main viewcontroller is called ViewController. in my second viewcontroller called PreferencesViewController I have a button that has to change some values in my main ViewController. But it doesn't...
I have set up a delegate protocol in my PreferencesViewController.h like I saw on a few examples on Stack Overflow (yes I did google it ;) ).
I also have imported the PreferencesViewController.h file to my main ViewController, aswell I told the viewcontroller to be the delegate: <PreferencesViewControllerDelegate>
I also implemented the method in my implementation of the main ViewController. But this method doesn't get called when I press the button. I implemented [self.delegate methodExample]; in to my IBAction
I've read a lot about setting the delegate. Where do I need to do this? do I need to create and alloc/init a instance of my PreferenceViewController? I tried this and then told the instance instance.delegate = self but that didn't work also...
Hope someone can help me out!

You're correct that you need to set the delegate. The easiest place to do this when using segues is in the source view controller (ViewController, in this case) using he prepareForSegue:sender: method. The segue object passed to this method has a reference to the destination view controller; you probably want to do something like:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"Your preferences segue identifier"]) {
PreferencesViewController *preferencesViewController =
segue.destinationViewController;
preferencesViewController.delegate = self;
}
}
Since you're using segues, the system is doing the alloc/init of the new view controller for you; this method is called by the system to let you do any hooking up of the new view controller before it's displayed.

Related

How to switch view controller under this circumstance

I have a view controller that I need to refresh it self so, I basically reload it with the following code.
-(void)check{
GameController*myNewVC = [[GameController alloc] init];
[self presentModalViewController:myNewVC animated:NO];
}
I can call the method above in gamecontroller and it works fine, but in a button sub class I use the method below and it doesn't work because nothing happens.
.h
#interface CellButton : UIButton {
}
.m
GameController*myNewVC = [[GameController alloc] init];
[myNewVC check];
What can I do to get this working?
I have a view controller that I need to refresh it self so, I basically reload it
Don't do that. Your view controller isn't refreshing itself, it's replacing itself, and it's hard to think of a reason that it should need to do that.
Put the code the loads the data in a separate method, and call that method on the existing view controller instead of creating a whole new view controller. For example, many view controllers that manage a UITableView will call the table's -reloadData method to tell the table to discard any cells that are currently visible and request new ones. No matter what kind of view(s) your view controller manages, you can do something similar.
I can call the method above in gamecontroller and it works fine, but
in a button sub class I use the method below and it doesn't work
because nothing happens.
That's most likely because you say you're using the code in a UIButton subclass, and the code says:
[self presentModalViewController:myNewVC animated:NO];
So, the button is telling itself to present the view controller. However, UIButton doesn't have a presentModalViewController:animated: method. I'm surprised that "nothing happens" -- I'd expect an exception due to the unimplemented method. It should work fine if you replace self above with a pointer to your view controller. Or, much better, put the code in an IBAction method in the view controller, set the buttons action to that method, and its target to the view controller.
(from your comment...)
There is a function in the button class that will dictate weather or
not the view controller will refresh it self.
That sounds like a poor plan -- in a well designed MVC application, logic that controls whether the view controller will refresh belongs in the view controller. Have the view controller enable/disable or show/hide the button based on whatever conditions control the refreshing behavior.

Using segues and nsnotificationcenter

I have 2 viewcontrollers and I want to send a notification out from one to the other and have a label changed based on the name of the notification (pressing a UIButton). I just started using segues and found they are a very useful way to get from one view to another. The problem I am facing is that using a segue (modal at the moment), the second view controller is not receiving the notification. I believe that segues release and create new view controllers when used, not sure. Is there any way around this?
Thanks!
I think using NSNotification is not the right method for passing data from one VC to another. Like Rog said, use prepareForSegue and use a property on the destination VC:
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
// Always check to make sure you are handling the right Segue
if ([segue.identifier isEqualToString:#"mySegue"]) {
MyOtherViewController *movc = segue.destinationViewController;
movc.myProperty = #"MyValue";
}
}
Use prepareForSegue for going-to a segue, and use the delegate pattern for coming back. Within prepareForSegue, set the originating viewController as the delegate of the destination viewController. When returning, have the destination viewController call it's delegate (the original viewController) for whatever method you implement.

iOS: How to Recognize that We Got Back from a Child UIViewController within the Parent UIViewController?

Let's say that I have 2 UIViewControllers on a stack within a UINavigationController. In the "parent" we call "[self.navigationController pushViewController:childViewController animated:YES];" upon some user action and in the "child" we call "[self.navigationController popViewControllerAnimated:YES];" upon some user action.
How can we recognize within the parent that we just got back?
Is there some "event" driven method that can recognize that this popViewControllerAnimated action was called from the child?
It seems like you're using this child controller as a modal in that it can be 'dismissed'. If that is the case, try to follow Apple's patterns that they use for UIAlertViews.
If that is the case, I'd do either of the following to implement a delegate pattern(delegate vs block is a huge debate that I will not get into here) so the owner(the one that pushes the child on) knows when its dismissed:
Create a protocol (ChildControllerDelegate), have one method in it childControllerWasDismissed:(ChildController *)
add a block property(make sure its a copy property, not retain) to the ChildController
You'll then want to call the delegate method or block on viewDidDisappear. If you want finer grain control, have a delegate method or block that corresponds viewWillDisappear / viewDidDisappear.
I'd successfully resolved this by setting navigationController?.delegate = self and then implementing this method to determine whether the current view controller is shown again after a pop.
func navigationController(navigationController: UINavigationController, didShowViewController viewController: UIViewController, animated: Bool) {
if viewController == self {
// we got back
} else {
// some other controller was pushed
}
}
There's a few way to hint at that. What you can do, is call the popViewControllerAnimated from the parent. You can do that by passing a block to the child controller that would then execute the said block and thus popping would be done by the parent controller.
You can also use the UINavigationController delegate to be notified when a UIViewController will be dismissed:
- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated;
This method will let you know which VC will be shown and you can check if the current (not yet popped) VC is the child you were looking for.
You can also do some trick with - (void)viewWillAppear: but this might require some hacks.
First read this, it will help you understand what is going on with view controllers.
Then implement viewWillAppear: and viewDidAppear: in your parent view controller to log a message.

How to call a method in another view when controller is dismissed

Basically the problem I am having is I am unable to call a method in my Main view controller(called Recorder) from another view called Table.
The table view is loaded as a Modalview controller(presentmodalViewController) from Recorder when the user clicks on a button. The table view lets my users change from setting 1 to setting 2 and has a done button (which calls dismissmodalviewcontroller) and returns the user to the main view(Recorder).
What I want is to call a method in Recorder when the done button is clicked on Table View. This method is called Changeview and changes the setting. I am currently unable to call this method properly.
The current code I have is:
changeView method
- (void)changeView
{
[levelsView changeView];
}
TableViewController interface file
RecorderViewController*recorderViewController;
#property (nonatomic, retain) RecorderViewController *recorderViewController;
TableViewController implementation file
#synthesize recorderViewController;
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
[recorderViewController changeView];
}
Method called when Done button is pressed
- (IBAction) Switch: (id) sender {
[self dismissModalViewControllerAnimated:YES];
}
The current code does not give me any errors but it also does not change the setting. I have also tried to setup notifications with no luck. Any insight into this?
Are you setting the value of recorderViewController when you initialize the tableViewController (i.e., are you setting tableViewController.recorderViewController = self in your Recorder class)? If not, then your call to [recorderViewController changeView] is sending a message to nil – which doesn't crash, but it doesn't do anything either.
As an aside, passing your TableViewController a reference to your RecorderViewController is probably not the best way for two controllers to communicate: You may want to consider using NSNotificationCenter, or passing a model object and using Key-Value Observing.

How is a delegate object called?

my protocol:
#protocol ElectricalSystemEngineDelegate
-(void)didRequestMainMenu:(id)sender;
#end
I designed this protocol in order to handle dismissal of a modal View Controller inside my rootView controller. My rootView controller adopts this protocol and is declared as follows:
#import "ElectricalSystemEngineDelegate.h"
#interface RootViewController: UIViewController <ElectricalSystemEngineDelegate>
//other ivars & methods including instantiation of my modalViewController.
I use an out-of-the-box:
-(IBAction)displayElectricalViewController
-to display the modal controller... which works fine. I am, however, confused on how to proceed further with the implementation of this protocol to handle dismissal of the controller..
//The implementation of my root view controller.
-(void)didRequestMainMenu:(id)sender {
[self dismissModalViewControllerAnimated: YES];
}
Obviously, I correctly implemented the protocol by using the prescribed method. I want the method to dismiss my view controller when called. I also want it to be called by the tapping of a back button in the modalViewController.
As the apple docs say, "In some cases, an object might be willing to notify other objects of its actions so that they can take whatever collateral measures might be required." My goal is for my ElecticalViewController to notify its parent (the RootViewController) that it should be dismissed. That dismissal should be triggered by tapping the back button. How does the object accomplish this notification?
You need to add id <ElectricalSystemEngineDelegate> delegate property to your ElectricalViewController.
Then you need to assign self (RootViewController) to that delegate after you created ElectricalViewController.
Then you call [delegate didRequestMainMenu] when you dispose ElectricalViewController.
Then you need to create a method didRequestMainMenu to your RootViewController.