Loading screen for iOS app - ios

I need a loading screen to show while some data is being downloaded from the server. I present a view controller with modal segue without animation. But I don't know how to dismiss the loading screen view controller since dismissViewController function can only be called from inside.
I should be able to dismiss the loading screen view controller from another view controller. Any suggestions?

One option is using NSNotificationCenter. You can post custom notification and listen it in loading view for closing it.
If you are getting the data in parent view then you can close the loading view from parent view also. You can call dismissViewController from parent view using presentingViewController property of UIViewController class.
In your case from parentView you can dismiss the child view using:
[self.presentingViewController dismissViewControllerAnimated:YES completion:nil];
presentingViewController
The view controller that presented this view controller. (read-only)
Declaration
Swift
var presentingViewController: UIViewController? { get }
Objective-C
#property(nonatomic, readonly) UIViewController *presentingViewController
Discussion
When you present a view controller modally (either explicitly or
implicitly) using the presentViewController:animated:completion:
method, the view controller that was presented has this property set
to the view controller that presented it. If the view controller was
not presented modally, but one of its ancestors was, this property
contains the view controller that presented the ancestor. If neither
the current view controller or any of its ancestors were presented
modally, the value in this property is nil. Import Statement
import UIKit Availability
Available in iOS 5.0 and later.

Do you need to show another VC? You could just show a subview, making it visible=true when you start the app, and on the request success or failure callbacks hide it again (depending on the networking framework you are using)
I don't know were you start the request and were you know when it is done, if the loading screen knows when the download is finished you can do one of two things, or you pass the first VC as a delegate (defining a protocol) to the second VC (loading screen), and when you know on the loading screen that the download is finished you call a method on the delegate that will dismiss the loading screen,
Or you can use NSNotificationCenter, register for some kind of events on the first VC and when the process finishes on the loading screen you notify the first VC with this method, to dismiss the loading screen.
If you start the process on the first VC, and you know when it ends also on the first VC I would not understand your question, as you would just dismiss the loading screen and it would work.
Could you give more info? If you'd like I can post some code in order to help you in one of this approaches.

Related

ViewController Modal Presentation not appearing

I have a view controller that is a child view controller of my window's root view controller. That child view controller has a table view and when i select a row it tells the parent view controller to present a view controller modally. The modal view controller, however, never appears. I created a bare bones test view controller that just prints viewDidLoad and viewWillAppear. What I notice is that when I call parentVC.present(testVC, animated:true, completion:nil), viewDidLoad is run, but viewWillAppear is not. viewWillAppear is only then called when I interact with the UI in some way. Whether tapping, panning, scrolling or whatever.
I've spent hours trying to debug this. It doesn't seem like the main queue is blocked and I've reduced the problem to its bare bones. The modally presented view controller's viewWillAppear is simply not called until I interact with the UI again.
What could be causing this symptom?
In comments, you mention that you're instantiating your view controller with
let vc = TestVC()
where TestVC is presumably a (largely empty) UIViewController subclass.
A view controller needs a view created either via either storyboard scene (using instantiateViewController), a NIB or, in very rare cases, a view you create in loadView (which you shouldn’t be confused with viewDidLoad).
I’d suggest creating a storyboard scene (assuming you are using storyboards), give it a storyboard ID, and then use instantiateViewController:
let vc = storyboard.instantiateViewController(withIdentifier: "foo")
But just having a UIViewController subclass called TestVC and instantiating it with TestVC() won’t work.
In our discussion, you said you wanted to do this programmatically with no NIB nor storyboard. If so, use loadView. See https://stackoverflow.com/a/37964249/1271826 for an example.

viewDidLoad vs ViewWillAppear in IOS

Please help me with this. I have created a simple project with two views as shown. I have attached the images for my storyboard and swift files. So, I read that viewdidload will be executed only once while loading the view into the memory. But, when I make a transition from secondview to the firstview the viewdidload is executing again and so is the print statement in the viewdidload method.
Someone please explain me this.
viewDidLoad is not called once for the Application. It is get called once for that viewController when the view holds memory and loaded.
So as many number of of time you push to the viewController, that many times it will call the viewDidLoad
viewDidLoad() — Called when the view controller’s content view (the top
of its view hierarchy) is created and loaded
viewWillAppear() — Intended for any operations that you want always to
occur before the view becomes visible.
For more info about this look at the link : https://developer.apple.com/library/content/referencelibrary/GettingStarted/DevelopiOSAppsSwift/Lesson4.html
So if the view is already in memory (Like your case), then no need to push again, only need to pop back by this code
self.navigationController?.popViewControllerAnimated(true)
You should not make transition from secondViewController to firstViewController for back. Pop the second view controller by this code to back:
self.navigationController?.popViewControllerAnimated(true)
When you make a transition it makes a new instance from your firstViewController but when you pop the second view controller it dismiss your secondViewController and shows your last viewed viewController again.
Or
in the case that you are not using navigationController you should use below code to dismiss your secondViewController
self.dismissViewControllerAnimated(true, completion: {});
The main point is that you should not use new transition for back.
The simplest way:
1.First embed your ViewController in NavigationController
2.Call to this (instead of create segue for backing)
navigationController?.popToRootViewController(animated: true)
viewDidLoad will be called only once

Link to another ViewController inside viewDidLoad method

in the viewDidLoad method i have this code.
When the application is running its not go to the another viewController, its gives me an error:
Warning: Attempt to present <CompleteCountryViewController: 0x7fb971779be0> on <ViewController: 0x7fb97176f3e0> whose view is not in the window hierarchy!
What can i do, that when the application running its will go to another viewController?
You should not present a view controller in the viewDidLoad method of another controller because you cannot show a view controller (present modally or push) when a transition is already occurring (push, pop, present, dismiss).
My suggestion is that you move the code in your code sample to the viewDidAppear: method. At this point, you know for sure that the transition has completed.
You seem to have a slight misunderstanding of the lifecycle of UIViewController if you want to modally present a view controller inside the viewDidLoad of another one.
viewDidLoad gets called in one view controller after it has been instantiated and its view components have been loaded (thus the name). The view of that view controller is about to be displayed, so it doesn't make much sense to instantiate another view controller at this point and present it on the first one.
Let me give you an example with two view controller A and B.
You instantiate A and its viewDidLoad gets called. So, A is about to be displayed! What you are doing in your code now is to instantiate B at this very point and show it on A. iOS doesn't like that and will give you your error.
I had an issue where I was attempting to present a modal view controller within the viewDidLoad method. The solution for me was to move this call to the viewDidAppear: method.
View controller's view is not in the window's view hierarchy at the point that it has been loaded (when the viewDidLoad message is sent), but it is in the window hierarchy after it has been presented (when the viewDidAppear: message is sent).

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.)

How to send message to a parentViewController that is a subclass of UIViewController?

I have a UIViewController (MyViewController) and another view controller i'm presenting modally though MyViewController (call it SecondViewController). I want to be able to send a message to MyViewController from SecondViewController by using
[self.parentViewController hideSecondViewController];
But since parentViewController is defined as a UIViewController, and hideSecondViewController isn't a method of UIViewController, I get a warning saying "UIViewController may not respond to 'hideSecondViewController'". It works fine, because it CAN send the message successfully during the program, but since I #import SecondViewController in MyViewController, I can't #import MyViewController in SecondViewController. Any way around this?
When it comes time to dismiss a modal
view controller, the preferred
approach is to let the parent view
controller do the dismissing. In other
words, the same view controller that
presented the modal view controller
should also take responsibility for
dismissing it whenever possible.
Although there are several techniques
for notifying a parent view controller
that it should dismiss its modally
presented child, the preferred
technique is delegation.
In a delegate-based model, the view
controller being presented modally
must define a protocol for its
delegate to implement. The protocol
defines methods that are called by the
modal view controller in response to
specific actions, such as taps in a
Done button. The delegate is then
responsible for implementing these
methods and providing an appropriate
response. In the case of a parent view
controller acting as a delegate for
its modal child, the response would
include dismissing the child view
controller when appropriate.
Read more at the View Controller Programming Guide for iOS.
P.S:
since I #import SecondViewController
in MyViewController, I can't #import
MyViewController in
SecondViewController.
To solve a circular dependency problem you can use a forward declaration.
It would be better to redesign your architecture as albertamg proposed but this should work:
[self
dismissModalViewControllerAnimated:YES];
you can call dismiss on both the presenting and presented view controller and it will do the same thing.

Resources