How to pass delegate between ViewControllers - ios

I have three View Controllers. Let's call them BaseVC, firstVC and secondVC. FirstVC is presented modally by BaseVC. SecondVC is pushed by firstVC. There is a one button on each firstVC and secondVC. By clicking them, I want to dismiss the current VC and let BaseVC do something. So I created a protocol, let BaseVC obey it, and set BaseVC as firstVC's delegate. When I set secondVC's delegate from firstVC, breakpoint show it succeeding. However when I call delegate from secondVC, it shows _delegate is nil.
Is it because delegate is always a weak property? So how could I pass delegate between View Controllers or is there any other way to solve this problem?

You can use postNotification while dismissing the VC and add the observer on baseVC to do some operation.
You could use [self.navigationController dismissViewControllerAnimated:YES completion:nil]; in button action to dismiss the view controller.
Before this you need to post the notification [[NSNotificationCenter defaultCenter] postNotificationName:#"NotificaitonBaseVC" object:nil]; and add the observer in baseVC's viewDidLoad method as follows
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(doSomeOperation:) name:#"NotificaitonBaseVC" object:nil];

Related

Dismissing view controllers all at once

I need to go back all the way to the view controller that presented the first navigation controller. However I haven't dismissed multiple controllers before at once, and when I've tried doing so, it doesn't work. It just goes to the first navigation controller instead of all the way to the one before it.
Here is my current code:
[(UINavigationController *)self.presentingViewController popViewControllerAnimated:NO];
[self dismissViewControllerAnimated:YES completion:nil];
I have a view controller which modally presents the first navigation controller. The first navigation controller screen is called Main View Controller. It then pushes to Login View Controller. Login View Controller does presentViewController to MenuViewController (UIViewController).
I need to get from MenuViewController all the way back to the view that presented the first navigation controller. Thanks.
Try this
UIViewController *vc = self;
while (vc.presentingViewController != nil) {
vc = vc.presentingViewController;
}
[vc dismissViewControllerAnimated:YES completion:nil];
One option would be to use NSNotifications.
You can add an observer in your first/root/initial UINavigationController subclass e.g.
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(logout:)
name:#"LogoutNotification"
object:nil];
Then in your "logout:" method you have direct control over the initial UINavigationController rather than those further up the hierarchy.
You can then send an NSNotification from anywhere in the app in order to trigger the method.
e.g.
[[NSNotificationCenter defaultCenter] postNotificationName:#"LogoutNotification" object:self];

how to refresh the viewdidload for parent viewcontroller

I have 2 viewcontrollers with segue "page curl"
viewcontrollerA => pagecurl => viewcontrollerB
and Now I want to update viewcontrollerA since user make some change at viewcontrollerB.
I tryed:
UIStoryboard* sb = [UIStoryboard storyboardWithName:#"mystoryboard"
bundle:nil];
UIViewController* vc = [sb instantiateViewControllerWithIdentifier:#"ExampleViewController"];
[vc ViewDidLoad]; // or ViewWillAppear or ViewDidApear
it works only for the NSLog I put in those functions.
but none of them works with the function which check out Coredata and update the interface.
please help
try this code:
you add parent class
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(actionremovecalender:)
name:#"subMitReport"
object:nil];
-(void)actionremovecalender:(NSNotification *)notification
{
[self ViewDidLoad]
}
call child class
[[NSNotificationCenter defaultCenter]postNotificationName:#"subMitReport" object:nil]
You can send a NSNotification that the parent will receive, or you can set a delegate with a method implemented by the parent view.
In both cases, just reload the view.
In a one-to-one relation, you should prefer the delegation pattern. Just add a weak reference of viewcontrollerA to your viewcontrollerB. You can just call a method (in this case viewDidLoad method) of viewcontrollerA using the reference so you can refresh the views. But I'd prefer declaring a protocol for delegation to prevent tight coupling of two view controllers.
ViewWillApear or ViewDidApear will be called since there is any object changes in the viewcontroller, but if you want to change your viewcontrollerA from another viewcontrollerB, that require NSNotificationCenter to call the function from viewcontrollerA
you can always use NSNotificationCenter to update your parent viewcontroller
At your parent viewcontroller put this:
//since child view controller calls turnItOff, notification center calls function "turnButtonCountinuesOff"
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(turnButtonCountinuesOff) name:#"turnItOff" object:nil];
turnButtonCountinuesOff is your function at parent viewcontroller
At your child viewcontroller put this:
//connect to parent UI view controller calls notification turnItOff.
[[NSNotificationCenter defaultCenter] postNotificationName:#"turnItOff" object:nil];
hope it helps.

Refreshing Viewcontroller?

I have two viewcontrollers in my storyboard project. Once I click the tableview row in ViewcontrollerOne then it will display the contents of that row by passing value and settext to that labels in viewcontrollerTwo. But when I tried a third viewcontroller and by clicking the button is third viewcontroller am sending same arrayname with different values but its not displaying in the label in viewcontrollerTwo.
Why? How can I refresh the viewcontroller on viewdidload or while moving to viewcontrollerTwo ?
Currently, I add this code to viewcontrollerTwo's viewDidLoad: method.
[self.view setNeedsDisplay]
You can reload your view controller by putting this in your applicationDidBecomeActive
[yourcontroller reloadInputViews];
However, why don't you reload your tableview as you are using same tableview.
you can always use NSNotificationCenter to update your parent viewcontroller
At your parent viewcontroller put this:
//since child view controller calls turnItOff, notification center calls function "turnButtonCountinuesOff"
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(turnButtonCountinuesOff) name:#"turnItOff" object:nil];
turnButtonCountinuesOff is your function at parent viewcontroller
At your child viewcontroller put this:
//connect to parent UI view controller calls notification turnItOff.
[[NSNotificationCenter defaultCenter] postNotificationName:#"turnItOff" object:nil];
hope it helps.

iOS - Call delegate method on main view from popover inner (pushed) view?

I need to call a delegate method on my main view controller ('showDetails:') from a popover view's pushed view (embedded in navigation controller). This is all from a storyboard setup.
The hierarchy is: Main view -> Popover (menu tableview embedded in navigation controller)->Popover secondary View (pushed onto popover navigation controller)
I know how to setup a delegate on the popover using prepareForSegue, but not on an inner view.
How can I call a delegate method on the main view from an inner (pushed) view of a popover?
Here is how I setup the delegate on a popover main view:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"segueSearchResults"]) {
//Dismiss User Popover
[self dismissUserPopover];
SearchResultsViewController *vc = segue.destinationViewController;
vc.searchDelegate = self;
self.searchPopover = [(UIStoryboardPopoverSegue *)segue popoverController];
self.searchPopover.delegate = self;
}
}
Instead Delegate i prefer "NSNotificationCenter" in your case
Add an observer to your ViewController for some action in uiview
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(receiveActionNotification:)
name:#"someActionNotification"
object:nil];
Post Notification from your pushed View in PopOverController
Post Notification and method in your Viewcontroller will be called
[[NSNotificationCenter defaultCenter] postNotificationName:#"someActionNotification" object:self];
At the end Dont forget to remove Observer.
[[NSNotificationCenter defaultCenter] removeObserver:#"someActionNotification"];
When you need to communicate between two view controllers which are far apart in the VC hierarchy, trying to reference one from the other so you can directly call methods on it doesn't work so well -- there's several levels of indirection in between, and it's very fragile if you change your VC hierarchy later.
Look into notifications (NSNotificationCenter) instead; you can have one VC "broadcast" info for another to respond to, regardless of where they are in your app.

Why doesn't backgrounding and re-opening an app call viewDidAppear?

I have 2 view controllers, vc1 and vc2. A modal segue is invoked from vc1 when I want to load vc2. Say I background the app when vc2 is showing. Why isn't viewDidAppear called when the app is re-opened to the view that was left off? How else am I able to detect every time vc2 appears?
You could register for the UIApplicationDidBecomeActiveNotification in VC2 and call viewDidAppear from there. Do this in your viewDidLoad of VC2:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(somethingThatWillCallViewDidAppear:)
name:UIApplicationDidBecomeActiveNotification
object:nil];
As rmaddy says below, make sure to remove the observer in dealloc or viewDidUnload.

Resources