Dismissing Popover and reload parentViewController - ios

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 ?

Related

iOS - Monitoring app flow from AppDelegate

I am trying to create Singleton that it would be initialised from AppDelegate. The purpose is to monitor all the UIViewControllers (the active one) and print on console the kind of class (as proof of concept). So my basic idea is to initialise the singleton in AppDelegate and pass as parameter a reference of AppDelegate. Then somehow I must monitor which one is the active view.
For example: View A B C
A is the first view in Navigation Controller. My Singleton knows that the current view is A. Then we push view B and Singleton is notified that view B is now the current view. Same with C. Now we pop C and Singleton knows that the current view is B.
Is any kind KVO or NSNotification for notifying my singleton that a new UIView is appeard/removed? Any alternatives for this problem?
After registering for all notification I found out about UINavigationControllerDidShowViewControllerNotification.
With this observer:
[notifyCenter addObserver:self selector:#selector(viewAppeared:) name:#"UINavigationControllerDidShowViewControllerNotification" object:nil]; I am able to monitor the activity of the UINavigationController.
You can get current View controller by just making a view controller object in appdelegate like
#property (strong, nonatomic) UIViewController *currentViewController;
and then on the view will Appear of your current view controller give the current reference to the app delegate object like
AppDelegate *myAppd = (AppDelegate*)[[UIApplication sharedApplication]delegate];
myAppd.currentViewController = self;
This way you get your current active view.
One approach is to pick a particular method you want to know about and intercept it.
Here, I create a category on UIViewController and provide a method I want called whenever the controller's viewWillAppear: would normally be called:
#include <objc/runtime.h>
#implementation UIViewController (Swap)
+ (void)load
{
NSLog(#"Exchange implementations");
method_exchangeImplementations(
class_getInstanceMethod(self, #selector(viewWillAppear:)),
class_getInstanceMethod(self, #selector(customViewWillAppear:)));
}
- (void)customViewWillAppear:(BOOL)animated
{
// Call the original method, using its new name
[self customViewWillAppear:animated];
NSLog(#"Firing %# for %#", VIEW_CONTROLLER_APPEARED, self);
[[NSNotificationCenter defaultCenter] postNotificationName:VIEW_CONTROLLER_APPEARED
object:self];
}
#end
After that, it's just a case of listening for the notification in whatever object needs to know (e.g. your Singleton).

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.

multiple view controllers involved, how to send a value back to starting view controller?

I am very new to iOS and overwhelmed with resources I find online. My use case is simple
a.) ViewController parent has label called categoryLabel. A tap on label category opens a new view View 1
b.) View 1, shows all groups. Lets says A, B, C. This will be shown on table
c.) when user click on any group A, B or C, a new view View 2 appears with all categories in that group. For example, user clicks on A and on View 2 user sees categories A1, A2, A3.
d.) Now when user clicks on any specific category, how does that goes back to ViewController parent and assigns to categoryLabel?
I do not know what is the best way to approach this design.
Any guidance is very much appreciated
hope this will help
let take an example , your are going from A -> B and want send some data from B to A , there are many technique to do that but using delegate method and block are nicer way.
delegate way :-
in your B.h file
#protocol yourDelegate <NSObject>
-(void)whichCategoryClicked:(NSString *)categoryName;
#end
#interface B : UIView
#property(nonatomic, assign)id<yourDelegate> delegate;
in your B.m
just call this delegate method after Clicking particular category.
[self.delegate whichCategoryClicked :#"Category_name"];
in your A.h
assign it as delegate and import the above class
#interface A.h : UIViewController<yourDelegate>
and in Implement this method in A.m
first in your viewdidload
{
B *objB = [[B alloc]init];
objB.delegate = self;
}
-(void)whichCategoryClicked:(NSString *)categoryName
{
categoryLabel.text = categoryName;
}
You can use Local notification for this purpose names as NSNotificationCenter in iOS. Which works as follows:
To send a notification that is from the view on which you are and want to send some value from that view, use below code:
NSDictionary *dict;
[[NSNotificationCenter defaultCenter] postNotificationName:#"NotificationKey" object:nil userInfo:dict];
and now on any of the view controller, you can add observer on viewDidLoad of that class as:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(methodToCall:)
name:#"NotificationKey"
object:nil];
Now call method written in above line:
- (void)updateImageFromArray:(NSNotification *)notification {
// your dict
NSDictionary *dictUserInfo = [notification userInfo];
}

1 delegate to 3 view controllers

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.

passing data to UIView before its loaded onto the navigation controller

I have a very complex situation (well for me) I am trying to resolve but thus far am having trouble with it.
I will outline the structure of the application now and then explain the problem I am having.
The names I am using are made up due to sensitivity of the data I am using.
secondToLastViewController // is a UITableView on the navigation stack
lastViewController // is just a normal UIView that i want to push onto the navigation stack
RequestClass // this class dose requests to my database and passed the data back to correct classes
getInfoClass // class is used for this specific request stores the information correctly and passes it back to secondToLastViewController
So as the user initiates didSelectRowAtIndexPath inside secondToLastViewController I make a request for the data using the RequestClass
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
//..
[RequestClass Getinfo:storedInfoPram];
}
now the thread shoots off to my RequestClass, which in turn queries the DB for some data which is then received and this data is passed off to my getInfoClass the reason I have done this is because there are dozens and dozens of different calls in RequestClass all doing different things, this particular request brings back alot of data I have to sort into correct object types so have created this class to do that for me.
anyway inside getInfoClass I sort everything into their correct types etc and pass this data back to secondToLastViewController in a method called recivedData, this is also where I think things are going wrong... as I create a new instance of secondToLastViewController the thing is I dont know how to pass the data back to the same secondToLastViewController that is already on the stack and was where the original request came from.
- (void) recivedData {
// do some stuff then pass data back to secondToLastViewController
SecondToLastViewController *sec = [[SecondToLastViewController alloc] init];
[sec sendGetSeriesArrays:pram1 Pram2:pram2 Pram3:pram3 Pram4:pram4 Pram5:pram5];
}
Now going back into SecondToLastViewController the thread lands in this method
- (void)sendGetSeriesArrays:pram1 Pram2:pram2 Pram3:pram3 Pram4:pram4 Pram5:pram5{
// call detailed view onto the stack
lastViewController *last = [[lastViewController alloc] initWithNibName:#"lastViewController" bundle:nil];
[self.navigationController pushViewController:last animated:YES];
}
after the thread reaches this point nothing happens... all the data is there and ready to be sent but the new view is never pushed to the controller stack.. and I think it is due to me declaring another version of secondToLastViewController when I am inside getInfoClass
what I would like to know firstly is how do I pass the recived data in sendGetSeriesArrays to the final view and secondly how do i even load the lastview onto the navigation stack?
Your observation is correct you are creating the secondToLastViewController instance again inside the getInfoClass. Dont do like that you have to use delegate/protocol approach for passing the data back to the secondToLastViewController.
Do like this
Define a protocol in getInfo class
getInfoClass.h
#protocol GetInfoClassProtocol <NSObject>
//delegate method calling after getting data
// I dont know the argument types give it properly
- (void)sendGetSeriesArrays:pram1 Pram2:pram2 Pram3:pram3 Pram4:pram4 Pram5:pram5;
#end
// declare the delegate property
#property (assign, nonatomic)id<GetInfoClassProtocol>delegate;
getInfoClass.m
- (void) recivedData {
// do some stuff then pass data back to secondToLastViewController
if ([self.delegate respondsToSelector:#selector(sendGetSeriesArrays: param2:)])
{
[self.delegate sendGetSeriesArrays:pram1 Pram2:pram2 Pram3:pram3 Pram4:pram4 Pram5:pram5];
}
}
secondToLastViewController.m
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
//..
RequestClass.delegate = self;
[RequestClass Getinfo:storedInfoPram];
}
Your secondToLastViewController should conform to the GetInfoClassProtocol
There are lots of ways you can accomplish this. In your revivedData function, instead of creating a new instance, you could:
1) Maintain a pointer to the navigation controller in getInfoClass, then you can get the last view controller from the view controllers on the navigation stack and use that. This will be the active instance of the view controller. There are ways to recover this from the window object, but those seem fragile and I would not recommend that approach.
2) You can pass a pointer to self from secondToLastViewController to your RequestClass getInfo call, then hold on to that and pass it back. This is probably a pain depending on the amount of code you have already.
3) You can maintain a static instance of the class if you will never have more than one secondToLastViewController. See How do I declare class-level properties in Objective-C?

Resources