Splash screen with heavy codes in monotouch - ios

We now that in monotouch and for iPhone / ipad application when we want to have splash screen before app lunch we should to set launch image in info.plist file and it will show this image before application launches.
But what is the best way to implement a splash screen when we want to have a splash that runs some heavy codes in background and not disappear until these operations had not completed? Some codes like downloading application config from internet and saving theme that often used in splash screen.

Possible solution:
Make a SplashViewController, which contains same image as app's splash image. Also it contains UIActivityIndicatorView;
In AppDelegate's FinishedLaunching method make new instance of SplashViewController, set it as window.RootViewController, call:
activityIndicator.StartAnimating();
Runs some heavy codes in background;
When it's done, set window.RootViewController to ViewController, which is app's starting point.

BTW, there is another solution: create main UIViewController, set it as Window.RootViewController immediately in AppDelegate's FinishedLaunching method. Then create and show modally splashViewController by this code:
...
MainViewController.PresentModalViewController(splashViewController, true);
...
Hiding modal UIViewController is possible via calling code:
DismissModalViewControllerAnimated(true);
Note that since iOS 6 PresentModalViewController becomes deprecated method. So, for many iOS versions compatibility you could code special method for showing modal UIViewController.
public void ShowModalViewController (UIViewController vc, bool animated)
{
if (UIDevice.CurrentDevice.CheckSystemVersion(6, 0)) {
MainViewController.PresentViewController(vc, animated, null);
} else {
MainViewController.PresentModalViewController(vc, animated);
}
}

Related

How to display lock sreen in task switcher and resume correctly

for the app I'm developing, I implemented a lock screen that allows the user to unlock the App by manual-pin or touch/Face-ID.
Everything is working OK during the normal use.
However, I need to show the lock screen when the app is resumed from background and even in the task switcher to avoid "peeking" at the content without having unlocked properly.
As recommended by Apple in this (old) article, I present the lock view controller in applicationDidEnterBackground:
func applicationDidEnterBackground(_ application: UIApplication) {
let lockVC = LoginViewController()
lockVC.loginType = LoginViewController.LoginType.resumeApp
if let topViewController = UIApplication.topViewController() {
topViewController.present(lockVC, animated: false, completion: nil)
}
}
where topViewControler is a useful extension to determnine the topmost view controller: Get top most UIViewController
.
The lockVC.loginType = ... is just to let the ViewController what type of login I need and customize its view a little bit
The results I get are a bit weird, both on simulator and real devices:
the task switcher preview for my app is completely black
when the app is resumed, the screen remains black as in preview and unresponsive. Only way to exit is to kill the app.
before obtaining the weird results above, I had to access all outlets as optional to avoid termination... that's fine for viewDidLoad stuff (I didn't expect the need for this when entering background, since the view had been loaded before - outlet wired) but the strange thing is that I had the same error for an IBAction in viewDidAppear (IBAction for touch-id button called automatically if touch/face-id is available - just a requirement).
I believe I'm missing something big here... but no other hints found.
No one of the ready-made lock screen solutions come with an example for the background/taskSwicth/resume case).
Note that the black/unresponsive screen seems to be same both if I use the mentioned extension for the topmost view controller to present or if I simply try to present it by
self.window?.rootViewController?.present(lockVC, animated: false)
(which I believe is wrong, but tried anyway)
Any help would be apreciated
I found a temporary workaround:
Display the lock screen when the app becomes active from background, as suggested by Dev_Tandel
Hide information in the task switcher by adding a blur effect on the current screen where the app is sent to background (applicationWillResignActive) and removing it when the app comes active again (applicationDidBecomeActive), as suggested here
As said, it's a temporary workaround that i wanted to share, but I don't like this 100%. It is required to show the lock screen in the task swtcher and Ive seen apps doing it (e.g. "oneSafe").
Still looking for help.
Solved, thanks to this post.
Apparently I was naive in trying to present a view controller with just its object instance.
If I use
let lockVC = topViewController.storyboard?.instantiateViewController(withIdentifier: "IDLoginViewController") as! LoginViewController
everything works, the lock screen is shown also in the task switcher, no need to blur!

Setting time for the launchscreen.xib objective c iOS

I am trying to set time for the launchscreen.xib to make it last longer, for example 5 sec,since by default it disappears too quick i searched the web but found nothing useful, can it be done ?
Thanks
The apple documentation mentions this:
A launch file or image provides a simple placeholder image that iOS displays when your app starts up. The placeholder image gives users the impression that your app is fast and responsive because it appears instantly and is quickly replaced by the first screen of your app.
So essentially the launch screen cannot be made last longer because its only displayed when the app is starting up.
Still if you want you can
create a custom UIView with the launch image
make it the Initial View Controller by dropping the arrow in storyboard to your custom UIView
present your main View Controller on top of the launch image view after x seconds using dispatch_after
You can add this in your app delegate:
float delay =5.0;
- (void)applicationDidFinishLaunching:(UIApplication *)application {
[NSThread sleepForTimeInterval:delay];
}
If you use a viewController, you can present it again in - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
making it the UIWindow's rootViewController, or presenting it modally from your application in the same method. This way, you can customize its dismissal. You can also add some animation to this viewController
So it may be another viewController than your launchScreen.

Changing rootViewController in applicaitonWillEnterForeground

Long story short, I'm trying to change my iOS app's rootViewController on applicationWillEnterForeground:, like so:
- (void)applicationWillEnterForeground:(UIApplication *)application
{
MyViewController *controller = [[MyViewController alloc] init];
self.window.rootViewController = controller;
}
However, when iOS performs the "zoom in" animation that is performed when an app is moved from the background to the foreground, it still shows the previous rootViewController's view. Then, as soon as the animation is complete, the app blasts the new rootViewController's view onto the screen.
One way to solve this is to simply move that code to - (void)applicationDidEnterBackground:, but the problem with this solution is that, in my app, there is no way to tell if a new rootViewController will be assigned until - (void)applicationWillEnterForeground:(UIApplication *)application (it is based on time passed since leaving the app).
How can I force the app to redraw before iOS performs the animation taking the app from the background to the foreground?
I believe this is not possible. The screen that iOS shows of your app when it comes into the foreground is actually a screenshot the system took when the app went into the background. There is no way to manipulate or replace that image at the time the app comes back into the foreground.
This behavior is partly documented in the Moving to the Background section of the iOS Application Programming Guide:
Apps can use their applicationDidEnterBackground: method to prepare for moving to the background state. When moving to the background, all apps should do the following:
Prepare to have their picture taken. When the applicationDidEnterBackground: method returns, the system takes a picture of your app’s user interface and uses the resulting image for transition animations. If any views in your interface contain sensitive information, you should hide or modify those views before the applicationDidEnterBackground: method returns.
Apple does not explicitly document that you cannot modify or replace this screenshot at a later time but neither do they say the opposite anywhere I know of.

What is the best way to create a loading screen class for a Monotouch App?

I need to load and process many things before my app starts, so when I test it on my iPhone it's always killed by iOS because it hangs the iPhone for too much time.
I then decided to write a loading screen class for my Apps, something that shows immediatly a logo and a progress indicator (keeping it responsive to avoid being killed by iOS), while in a background a separate thread initializes all my ViewControllers and then closes the loading screen and shows the main window.
What is the best way to do it with MonoTouch?
Any suggestion is welcome.
Thank you.
This is how I do it:
In the FinishedLaunching method, initialize and add your splash view to the main window:
window.AddSubview(this.splashView);
After that, invoke your code that does all the stuff you want to do in a thread/async invocation. I usually use the ThreadPool. Remember to invoke on the main thread:
ThreadPool.QueueUserWorkItem(delegate {
this.BeginInvokeOnMainThread(delegate {
//Initialize stuff here
//...
//when done, add your initial view to the window and remove the splash view
//eg.:
//window.AddSubview(myController.View);
//this.splashView.RemoveFromSuperview();
});
});
// show the window, which only displays the splash view now and return
window.MakeKeyAndVisible();
return true;
A rough example, but I hope it helps.

Show MBProgressHUD on iPhone app's splash screen while Core Data store is migrating to new version?

If my iPhone app needs to update the Core Data database, I would like to show an MBProgressHUD view to users while my iPhone app is loading, so they know that it's working and not hanging. How might I go about adding an MBProgressHUD to the splash screen while the data store is migrating? Normally I would attach it to the UIViewController's view, but the splash screen is under the app delegate. Is this possible to do?
No it is not possible to overlay anything over the splash screen as it's static.
You could, however, delay the intensive process for a bit until the app loads, then create a fake splash screen with the progress indicator while the intensive stuff goes on in a background thread.
You could create a #define macro in your application delegate header file (or in a "globals" header), like so:
#define MyAppDelegate [[UIApplication sharedApplication] delegate]
Then, when you want access the application delegate property, you can do so like this anywhere in your application you have imported that header (or the globals header):
MyAppDelegate.property = foo;
[[MyAppDelegate property] bar];
This may help you manage your progress view at any point in the app's life.
EDIT
sudo rm -rf is correct that you can't do work during the splash screen. But you can start your progress view in the app delegate's -applicationDidFinishLaunching: method, and then launch work on a background thread. Once your background thread's work is finished, have a callback dismiss the progress view.

Resources