iOS: Refresh a ViewController from a popOver - ios

I'm working on a problem where I have a ViewController which opens a popOver when a button is pressed and then in the popOver you can edit some settings which affect the content shown in the mother ViewController (for instance change the color of the View, change a map or a table there). This can be off course called whenever the popOver is dismissed, but it needs to be live up-to-date.
I tried using delegates, where I can pass over data or call a function but the function won't be started on a ViewController wchich isn't active, right?
I also tried NSNotifications but it didn't work either.
I found several questions like this on stackoverflow, but there is no real answer yet:
UIPopoverController button selecting method of another ViewController but not updating its view iOS
Refresh the view controller from popover
Refreshing a view from a popover
Refresh a WebView in a ViewController from another ViewController
how to refresh or reload a uiviewcontroller
Can somebody please explain a generall way with some code snippets how to get this fixed?

Delegation is a fine solution. The target view controller is presumably still visible underneath the popover (which shouldn't fill the screen). In this case when the target receives the delegate callback it can do any updates and refresh its views to update the UI without any limitation. In this situation both view controllers (the 'target' and the popover) would both be classed as 'active' as they are both visible on screen.

Related

viewDidLoad and viewWillAppear with tab bar controller

I'm looking into the viewDidLoad and viewDidAppear methods to better understand what they both do and I came across an article which uses the example of a banking application to explain how these methods work:
Consider a banking application that shows your current balance. A user
can tap on a button, which presents a list of nearby ATMs in a modal
view controller. In order to get the list of nearby ATMs, the
application must make a core location and web service request.
In this situation, a programmer could get away with requesting the
list of nearby ATMs from the server in viewDidLoad. The view
controller is only presented once, both viewDidLoad and
viewWillAppear: will be called back to back and only once for that
particular view controller instance. The net effect of the code in
either of these two methods will be the same.
But this is a bad idea. Consider what would happen if you wanted to
move the ATM view controller into a tab bar controller. Now, the ATM
view controller – with its ATM fetching code in viewDidLoad only
fetches the list of ATMs once. So you are in Atlanta on Tuesday, open
up your application to look for an ATM, then check your balance. Then
you travel to New York on Wednesday, re-open the banking application,
and you only see ATMs in Atlanta. The view was already loaded, no need
to call viewDidLoad and now you’re looking at stale data.
Sadly, I still don't fully understand how/why both viewDidLoad and viewWillAppear will be called 'back to back', or what adding the ATM view controller to a tab bar controller means in terms of these methods.
viewDidLoad method will call only once a life time of viewController and that is when viewController object will first load in memory.
where as viewWillAppear method will call every time when a view will appear to screen or you can say will be topViewController...
Explanation:
Consider you have tab based app with two tabs. Tab1 associated with viewController1 and tab2 is associated with viewController2. Now when you will run your app and you will see tab one is selected and viewController1 is on view and you want to change to tab2, when you will tap on tab2 then tabVieController2's object will create and load to memory first time hence its viewDidLoad method will call, and soon after that it will appear to window and viewWillAppear will also get call.
Now if you you try changing tabs by click on them only viewWillAppear methods will get called for both, as they are in memory already.
It simple, viewDidLoad get called when the view is load in, either via NIB, storyboard or with the loadView method. The viewWillAppear: is called when the view is presented.
When a view is added to a tab bar it only gets load once, thus the viewDidLoad will only be called once. But if the user switch to an other tab and back to the same view the viewDidLoad will not be called. This is because the view is already loaded.
However the viewWillAppear: is called in both cases just before the view is shown. Thus this will be called when the user first opens the tab and when it switches back to that tab.
I think they are referring to the fact that the view is loaded every time the modal view controller appears (thus the data is constantly refreshed) but only once when it is part of tab bar (only loaded on app launch). Kind of a whacky example to explain the methods though.
You might want to read up on the view controller lifecycle to know when to implement what in which method:
Responding to Display-Related Notifications
View Loading and Unloading

Become first responder app delegate not working

My situation goes as follows: I have an app which has a PIN screen implemented. Its nothing high-tech just basic 4 UITextFields and implemented logic via UITextFieldDelegate - it works.
I'm showing this screen in app delegate on -(void)applicationWillEnterForeground:(UIApplication *)application event. I am using MMDrawerController from github (link: https://github.com/mutualmobile/MMDrawerController) as the main view controller. If the current view presented when the application enters background and foreground again is this MMDrawerController then the becomeFirstResponder is not working - it doesn't show the keyboard. If there is another view controller presented on top of drawer controller the when entering foreground (let's say settings view) then keyboard appears normally.
I have tried NSLoging the canBecomeFirstResponder property and its set to YES. What is going on? How to fix this?
I can paste code if needed but its nothing ambiguous. Just plain call becomeFirstResponder.
EDIT:
To explain things a bit more clearly. rootViewController is a view controller caleed LoginViewController and it alloc-inits the sidebar and the center view controllers, alloc-inits the drawer controller and hooks everything up so it works. The app delegate view is actually a PIN screen which pops up when the app enters foreground. Now the keyboard appears like it should for the first time the drawer is visible.
When the user pops up SettingsViewController (yes, this is another view controller accessible from the sidebar view controller) it works as well. But when the user dismisses the settings view controller keyboard doesn't appear anymore. It has to do something with the drawer cause I tried without it and it worked (but I only had sidebar or center view controller visible).
Ideally you would want to access the textField within the MMDrawerControllers currentView. I have achieved something similar with this implementation:
In your app delegate store a reference to the DrawerController like so:
In AppDels interface:
#property(nonatomic, strong) MMDrawerController *appDrawController;
Then after you create the local drawer controller in didFinishLaunching (if you followed the setup instructions for this library):
self.appDrawController = drawerController;
In your applicationWillEnterForeground:
THECLASSTHATCONTAINSTHEPINVIEW *yourClass = self.appDrawController.centerViewController.childViewControllers[0];
Now you can access the public methods/properties, so:
[[yourClass pinEntryField] becomeFirstResponder];
Does this help at all ?

Showing master view on some pages and preventing the user from hiding it

I have an iPad app with a UISplitviewController set as the root view controller of UIWindow. The master view controller (i.e. the view controller of the left view) is the UISplitViewController's delegate with the delegate method shouldHideViewController returns YES, this means when the app first launches the left view will be hidden and can be shown (and hidden) by the user gesture, i want to show the master view when i navigate to detail pages and prevent the user from hiding it using the gesture, i've tried to call shouldHideViewController method on the delegate to let it returns NO the second time it got called but this time it has no effect, the master view keeps hidden in detail pages and can be shown with the user gesture.
any ideas to achieve showing of the master view with this scenario would be highly appreciated.
This may only be a partial answer because I'm not sure what you mean that you call shouldHideViewController method on the delegate. My understanding is that only the UISplitView should call this method. If you call it, then it will not effect the UISplitView, because it wasn't what made the call. In other words, the delegate method is used by UISplitView to get some information (and allow you a place to do additional things to other stuff) but it is not used as a way to tell the UISplitView what to perform.
Having said that, at least for the gesture activation/deactivation, I would think that in splitViewController:shouldHideViewController:inOrientation: you could do something like
[svc setPresentsWithGesture:NO];
I don't see any way to programmatically tell the UISplitViewController to display or hide the master view controller because the delegate only tells it if it should proceed in presenting or hiding the master when it is going to try and do that. It does seem like there should be a way to do this though.

how to dismiss a popover and show an activity indicator while doing more processing

Converting an application to work on iPad. Need some help in understanding the sequence of processing popovers, dismissals and activity indicators.
Here is the desired sequence:
Present a tableview wrapped in a navigation controller inside a popover.
Select a row from the table.
Send info from that row to the primary view controller (parent).
Dismiss the popover completely.
Show an activity indicator showing that processing is occurring.
Do some processing.
Make the activity indicator disappear.
Draw the graphics on the primary view.
I have been able to do all the above except the popover stays on the screen until all the processing is done and the graphics drawn. The activity indicator shows up momentarily when the popover disappears. I have tried delegates, notifications and setters, to no avail. It appears that all the processes inside a method don't necessarily execute in sequence and the popover view holds on until everything is executed (in this case the select row method).
Where do I put both the processing code and the activity indicators so everything works in the right order?
This is a very straight forward implementation
Check the following list
Create a delegate of the viewController shown in popover
Set the delegate of popover viewController as main viewController
Keep a reference of popover in main viewController to dismiss it once event is received.
Once event is received dismiss the popover after getting the selected value
Show an activity indicator view or HUD
Dismiss the activity indicator once processing is done
Source code for a demo app doing this.
Make the UIPopoverController instance a iVar. Alloc Init it with your required view controller on some button method or whatever you have designed. Make a protocol from your popover controller's root view controller and make the parent view controller conform to it. On the didSelectRowAtIndexPath: method, call that delegate to popover's parent view controller. On the message reception in parent view controller, dismiss the popover controller instance and do your processing there. (Do Manage the memory well if the project does not support ARC because the popover might be alloc inited several times.)

Memory management of view while using NavigationController

I changed navigation in my application from using UITabBarController to u UINavigationController. I.e. former solution (1st version) was based only on the TabBarController - 4 ViewControllers (one simple TableView, one simple custom view and one MapView with many overlays). The second version is based only on the UINavigationController.
In case of TabBarController it was clear and simple, everything worked fine, especially MapView. I mean: the MapView was loaded once (with a significant number of overlays) and when I went to another view and back to the MapView the MapView was still there with its overlays already loaded and displayed (simple check: MapView`s viewDidLoad was called just once per app run, I had some debug messages there).
Now I changed navigation logic to the UINavigationController. Everything works fine for the first look - but: the viewDidLoad (for each view) is called everytime I navigate to the view. It is annoying especially in the case of the MapView - the loading of overlays is performed everytime, it takes some time and it causes app crash in some cases.
OK, my questions:
Is it some kind of "common" behavior of NavigationController?
Can I change this behavior so viewDidLoad will be called just once?
And more - How can I influence the "display sequence" of some view?
I understand the logic is probably more complicated but I appreciate any answer or hint ;)
Some related circumstances:
TabBar and Navigation controllers are not combined.
I use storyboards, segues are designed in the UIB, no manual calling like perfomSegue or prepareForSegue in my code. One button triggers segue to MapView.
I use push segues.
I also tried to use modal segues but without any change of that behavior.
any of viewDidUnload is never called during segues among the views.
No memory warning received.
No memory leaks measured both on simulator and iPhone 4.
I tried to build a very simple temporary project / app that is concerned just about the Nav. Controller and other views without ANY coding, just storyboard. It was the same behavior.
There was an issue that causes app crash when I fast and periodically tapped to navigation button and back button between one view and the MapView. In most cases the app crashed when I tapped the back button on the MapView before it was fully displayed (i.e. its overlays). It was fixed when I added a 1 sec. delay method call in the viewDidDisappeared in the MapView. It is not a fair fix, I know ;)
A UITabBarController and UINavigationController are based on fundamentally different paradigms.
The UITabBarController is intended for the UIViewController on each tab to exist independently of each other and for the user to choose which they want to view. viewDidLoad only gets called once for each UIViewController because it is intended that each tab still exists in memory even as the user switches to a different tab.
The UINavigationController is a stack of UIViewControllers where each is related to the one above and beneath itself. The top UIViewController in the stack is always the one that is visible to the user. When a UIViewController is pushed to the stack, its viewDidLoad gets called because it is being loaded into memory. When the top UIViewControllergets poped off the stack, it is unloaded from memory, and viewDidUnload gets called on the way out (viewDidUnload is deprecated in iOS6 and won't get called, but the controller will still get dumped from memory). This is why viewDidLoad gets called every time that the user pushes a particular UIViewController onto the UINavigationController stack.

Resources