1 delegate to 3 view controllers - ios

I have a cameraViewController that is essentially a barcode scanner. I also have 3 view controllers (A, B and C) each with a button that lead to this cameraViewController.
When cameraViewController scans a barcode, it does the following:
if (self.detectionString != nil)
{
[self.delegate cameraViewController:self withCardNumber:self.detectionString];
[self.navigationController popViewControllerAnimated:YES ];
break;
}
It has a delegate and sends the detected string back to the previous/parent view controller.
All three viewControllers have the following methodimplemented:
#pragma mark - CameraViewControllerDelegate
- (void)cameraViewController:(CameraViewController *)cameraViewController withCardNumber:(NSString *)number
{
self.CardNumbertext.text = number ;
}
So both methods work with cameraViewController and viewControllerA. However, when the parentViewController is B or C, the cameraViewController still pops back to the right controller but the delegate function does not run. What am I doing wrong?

It's iffy to have just one instance of cameraViewController and three different view controllers that "fight over it" by each setting the cameraVC's delegate to themselves. I think it's a better use of system resources and better architecture if each of the A, B, C viewcontrollers responds to the button press by instantiating a new instance of CameraViewController and setting that instance's delegate to self. This should fix your issue and improve memory management/leak issues as well.

Post a notification to NSNotificationCenter, it's a much better solution to this problem :)
https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/nsnotificationcenter_Class/Reference/Reference.html

If you want keep the current implementation then update the delegate when you are presenting ViewController A,B and C. From the way you described in the question seems like you need to do this in -(void)viewWillAppear or -(void)viewDidAppear. Or use the notification manager as the OP suggested or else use blocks.

Related

How to call function from one viewcontroller to another controller?

SettingsStore.h
#interface SettingsStore : IASKAbstractSettingsStore
{
#public
NSDictionary *dict;
NSDictionary *changedDict;
}
- (void)removeAccount;
#end
menuView.m
-(IBAction)onSignOutClick:(id)sender
{
SettingsStore *foo = [[SettingsStore alloc]init];
[foo removeAccount];
[self.navigationController pushViewController:foo animated:YES];
exit(0);
}
I want to call this removeAccount function from menuView.m. But I am getting error.
How to fix it and call this removeAccount.
There are few mistakes in your Code please find them below.
[foo removeAccount]; Calling this method is correct
[self.navigationController pushViewController:foo animated:YES];
Not correct because SettingsStore is not subclass of
UIViewController only subclass of UIViewController can be pushed to
Navigation controller
exit(0); Calling this method is not
recommended by Apple
You are calling removeAccount correctly from your menuView.m file, but there are several issues with your code:
You are treating foo as though it were a UIViewController, and it's actually a member of the SettingStore class. Does the SettingStore class refer to an actual screen, or is it more a data object (for storing settings?). If it's the latter, you don't want to push it on. You can create it, and use it, but the user doesn't need to see it.
You are calling exit(0); you can remove that line. If you want to remove the menuView.m file from your memory, remove references to it (e.g. from its parent view controller).
The menuView.m file is confusing, as in, is it a view or a viewController. An IBAction I would normally stick in a ViewController file, rather than a view file. Your basic design pattern is MVC (Model / View / Controller). In this case, it seems your SettingStore file is a Model (data), the menuView.m is a View and your code is for the Controller bit.

Need To Pass The Value From B Viewcontroller to A Viewcontroller Using Objective C? [duplicate]

This question already has answers here:
Passing data between view controllers
(45 answers)
Closed 7 years ago.
I am struggling on calling method from viewController B to viewController A. Need to call viewController B close button click to Dismissviewcontroller then immediately need to call one method and want to pass two string values on viewController A. Its like reverse process.
FYI : I am using Storyboard and present viewController for B. A is the mainviewcontroller.
use viewWillAppear in controller A.
Post a notification from controller B and add
observer on controller A.
Post notification on controller B close button
[[NSNotificationCenter defaultCenter] postNotificationName:"NAME" object:nil userInfo:nil];
Add observer on controller A:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(perform:) name:#"NAME" object:nil];
Implement delegates on
controller B and implement it on controller A so once you click
on close button controller B just call the delegate and perform what ever you want.
Implement KVO
well the easiest way but not the most efficient is to make a global object of the viewController A and viewController A view did load method
call that global variable and make it equal to self and
in then the dismiss from viewController B
will use
[self dismissViewControllerAnimated:YES completion:^{
// here you can create a code for calling the global **viewController A** object to call the function you need
}];
conclusion :
in viewController A header file :
extern A* AGlobalInstance;
and in A.m file just below the #import "A.h"
A* AGlobalInstance;
and in the viewDidLoad
- (void)viewDidLoad {
[super viewDidLoad];
AGlobalInstance = self;
}
then in B.m button just use
[self dismissViewControllerAnimated:YES completion:^{
[AGlobalInstance function];
}];
but you must go to A viewController first before going to B to make it work
As the above answers suggested you to use Delegates and Notification so I am not gonna suggest you those. Apart from them I would like to ask you to go for Block.
typedef void(^valueHandler)(id anyObject1, id anyObject2);
#viewController A
B *instanceOfB;
[instanceOfB setValueHandlerBlock^(id anyObject1, id anyObject2) {
// Here you can receive the values.
}];
#viewController B
#property (nonatomic, copy) valueHandler valueHandlerBlock;
//To pass the value
if (valueHandlerBlock) {
valueHandlerBlock(#"a String value", anArray);
// When ever the above line will execute it will pass the values to view controller A.
}
There are many option for passing values
Use protocol and delegates
Use unwind segues
Use Notifications
there are many other option to do the same google on above points you will get tons of demos for this.

Dismissing Popover and reload parentViewController

I m actually new to developing iOS application. I currently developing an iPad application where there is two UIViewController (A and B).
A is my parent view controller and B is my UITableView popover that don cover the entire A.
After a row select at B, i manage to dismissed B but it don reflect changes made to A.
How do i reload the parent view or is a something like android called the onResume method.
Or ways to solve this problem.
Please provide me with some pointers, have being stuck for hours. Thanks
It depends on the situation. I would suggest 2 ways:
As someone mentioned before, you can make a delegate mechanism so that controller B can call something like -reloadData on controller A. This is a tight coupling but can solve your problem.
You can post a NSNotification from controller B and then listen to it in controller A. In controller B:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// Do your logic here
[[NSNotificationCenter defaultCenter] postNotificationWithName:#"SettingsSavedNotification" object:nil];
// Dismiss B controller
}
And in controller A:
- (void)viewDidLoad
{
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(didReceiveSettingsSavedNotification:) name:#"SettingsSavedNotification" object:nil];
// Proceed with controller/view setup
}
- (void)didReceiveSettingsSavedNotification:(NSNotification *)notification
{
// Reload data here
}
Don't forget to call -removeObserver:name:object: on controller A teardown.
Use – popoverDidClose: NSPopover class delegate method for update your data, or you may use cocoa binding.
Two things:
1) You want to make sure you are the delegate to the UIPopoverController you are using to show your popover view controller "B". See the docs here: https://developer.apple.com/library/ios/documentation/uikit/reference/UIPopoverControllerDelegate_protocol/Reference/Reference.html
Then you'll want to implement one of those methods, e.g.:
- (void)popoverControllerDidDismissPopover:(UIPopoverController *)popoverController {
// Reload my view controller "A"
}
2) How do you know which row was selected in view controller B? It's possible you're updating some singleton that both view controllers have access to, but a better design pattern might be to create your own protocol and for view controller "A" to conform to it. In that case view controller B should have a weak delegate property that it sends a message to when the user selects a row. Just look at another class that uses the delegate/protocol pattern to see how it works, you could even look at the .h file of UIPopoverController by CMD + clicking the class name, or CMD + Shift + O to the file name.
Cant you just use - (void)viewWillAppear:(BOOL)animated ?

Communiacting between UIDatePicker and UITableView

In my project I have 3 controllers;
NavigationController
ServiceTableViewController
DateTableViewController
The ServiceTableViewController is the initial view controller. It has several rows which prompt the user to enter in data, which will be emailed to a particular email address. One of the rows, when tapped, sends the user to the DateTableViewController which prompts the user to select a date from the UIDatePicker.
The issue I am facing is getting data back from DateTableViewController in order to display a label on the ServiceTableViewController to show the date the user selects in the DateTableViewController. I know how to get information from one view controller to another, but to go in reverse, so to speak, is not something I know how to do. Any help is appreciated.
Take a look at this:
https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/CocoaFundamentals/CommunicatingWithObjects/CommunicateWithObjects.html
There are couple of ways to pass data back and forth between view controllers.
Delegates
Target-Aciton
Notification
KVO
but honestly delegates are really all you need really and it sounds like in your current case.
see this -> (Passing Data between View Controllers)
Having said that, if you use delegates, here is how ---
setup a protocol in DateTableViewController.h at the top like so:
#protocol DateTableViewControllerDelegate <NSObject>
- (void)userSelectedThisDate:(NSDate *)d;
end
put this with the other properties
#property (nonatomic, weak) id <DateTableViewControllerDelegate> delegate;
and in DateTableViewController.m with the date to send back
[self.delegate userSelectedThisDate:withTheDateToSendBack];
in and ServiceTableViewController.h add
#import "DateTableViewController.h"
#interface ServiceTableViewController : UIViewController <DateTableViewControllerDelegate>
and since you are UINavigationController, somewhere in ServiceTableViewController.m add this when you are about to push to the DateTableViewController
DateTableViewController *vc = [[DateTableViewController alloc] init];
self.delegate = self;
[self.navigationController pushViewController:vc animated:YES];
and finally put the delegate method in ServiceTableViewController.m
- (void)userSelectedThisDate:(NSDate *)d {
NSLog(#"%#", d); // this should show the returned date
}
Research delegate pattern (here) (a heavily used pattern within Apple frameworks). You want to define a delegate protocol which allows to a date to be passed to the delegate.
You could implement the pattern as an #protocol with a single method and a property on the DateTableViewController. The ServiceTableViewController sets itself as the delegate before pushing the DateTableViewController.
Or, you could implement using a block. Again, the ServiceTableViewController sets the block before pushing the DateTableViewController.

Return to root view in IOS

To some this may sound like a daft question. I've searched around, and found little, mostly because I cannot find the appropriate search terms.
Here what I want to do is:
The application begins at view A.
View A launches view B, and view B launches view C.
Is their a way for view C to return directly back to A without dismissing itself and thus exposing B. For example a main menu button.
You can call popToRootViewControllerAnimated: if you have a UINavigationController. If you specify NO to animate it, then it will just jump back to the root without showing B first.
I have discovered a solution to my problem. Its a bit dirty, (and I''ll probably get shot down in flames for it) but works very well under tests and is very quick to implement. Here's how I did it.
In my app I have a Singleton class called GlobalVars (I use this for storing various global settings). This class holds a boolean called home_pressed and associated accessors (via synthesise). You could also store this value in the application delegate if you wish.
In every view controller with a main menu button, I wire the button to the homePressed IBAction method as follows. First setting the global homePressed boolean to YES, then dismissing the view controller in the usual way, but with NO animation.
-(IBAction) homePressed: (id) sender
{
[GlobalVars _instance].homePressed = YES;
[self dismissModalViewControllerAnimated: NO];
}//end homePressed
In every view controller except the main menu I implement the viewDidAppear method (which gets called when a view re-appears) as follows.
-(void) viewDidAppear: (Bool) animated
{
if ([GlobalVars _instance].homePressed == YES)
{
[self dismissModalViewController: NO];
}
else
{
//put normal view did appear code here/
}
}//end viewDidAppead
In the mainMenu view controller which is the root of the app, I set the global homePressed boolean to NO in its view did appear method as follows
-(void) viewDidAppear: (Bool) animated
{
if ([GlobalVars _instance].homePressed == YES)
{
[GlobalVars _instance].homePressed == NO;
}
else
{
//put normal view did appear code here/
}
}//end viewDidAppear
There, this enables me to go back to the root main menu of my app from any view further down the chain.
I was hoping to avoid this method, but its better than re-implementing my app which is what I'd have to do if I wanted use the UINavigationController solution.
Simple, took me 10 minutes to code in my 9 view app. :)
One final question I do have, would my solution be OK with the HIG?

Resources