How to call a view controller from AppDelegate in iOS - ios

I am creating an iOS app in which I have the following requeriment: the app should show the login screen when it starts the first time and also that screen must also be shown when the app comes from the background to the foreground, in case it has been sent to background during run time.
I have handled to show the screen in both cases. However, when I do it and the app comes from the background, and I click the texfield to type my password, the app gets frozen, and it fails in a thread that I don't know what it means.
I call the screen to be shown when the app comes from background like this, in the applicationWillEnterForeground, in AppDelegate:
self.window=[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
RoomRootViewController* room = [[RoomRootViewController alloc] init];
[[self window] setRootViewController:room];
[self.window makeKeyAndVisible];
Is this the correct way to do so?
Thanks a lot in advance ! I am completely lost with this as I am very new in iOS, so any help will be very appreciated.
Attached in an image you can see where the app fails.

The code you are currently using is completely deleting the root view controller of your app window, in other words, you are deleting all the views and view controllers in your app. If you are not using ARC, this is just one huge memory leak. If you are, it's still not a very good idea.
In your applicationWillEnterForeground: method, try using this code instead:
RoomRootViewController* room = [[RoomRootViewController alloc] init];
[self.window.rootViewController presentViewController:room
animated:NO
completion:nil];
This will display the RoomRootViewController over the top of all your app's current views, instead of deleting them. You can then dismiss it like this:
[self.window.rootViewController dismissViewControllerAnimated:YES
completion:nil];
and easily return to the rest of your app.

It will be very messy if you are using this line of code
self.window=[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
It means every time you are creating new instance of UIWindow which will contain UIViewController and all other component each time. Which means when you go to background and comes to foreground the old window instance has been flushed off and it will contain new components that's why when you click on the UITextField it has been deallocated, The reason you are getting error. Don't create new instance of window and use the code as #PartiallyFinite does.
Hope this helps.

Related

iOS app crashing after setting UIWindow rootViewController in iOS 9

My app was working great until running it on iOS 9.
In the AppDelegate, I check whether the user is logged in or not. If they're not logged in, I send them to the login screen with the following line:
self.window.rootViewController = [self.window.rootViewController.storyboard instantiateViewControllerWithIdentifier:#"Login"];
After the user logs in, I attempt to send them to the main app with the following line:
self.window.rootViewController = [self.window.rootViewController.storyboard instantiateViewControllerWithIdentifier:#"Tabs"];
This worked in iOS 8, but now it crashes the app. And it's a bad crash. The whole device has to reboot (although it's a very quick one, so I think it's more like a SpringBoard reboot or something).
I'm seriously at a loss as to why the first line works and the second doesn't. Any help is much appreciated!
EDIT
I ended up recreating the entire UIViewController flow that was crashing and it works fine now. As far as I can tell it was some strange bug in the new Xcode. Not considering this an answer, so if anyone has a true answer then feel free to share it.
Not sure why, but this works for me in iOS9. It might be that you're trying to do this already in the AppDelegate before the window has been properly loaded?
I've got a first ViewController in the storyboard and does this redirecting there instead.
UIViewController *viewController = [[UIStoryboard storyboardWithName:#"Storyboard"
bundle: nil] instantiateViewControllerWithIdentifier:#"viewController"];
[[[[UIApplication sharedApplication] delegate] window] setRootViewController:viewController];
The code to set the root view controller works in iOS9 without issues.
[[[[UIApplication sharedApplication] delegate] window] setRootViewController:viewController];
If you get a crash in that line, it surely means that the viewController initialization logic or any of its subviews are throwing at some point.
Problem is that working in the simulator the app will crash with no errors in the output. Best thing to do here is setting a breakpoint in the viewController logic (ie: viewDidLoad) and check what line is causing the error.

Getting top UIWIndow/UIView on device using public/non-public/private API

I'm trying to find out how to find the top most view using non-public/private api, is there any way doing it (iOS 7.1.2)?
Edit:
Maybe I wasn't clear,
I want to get the top most view no matter what app is active now (facebook, whatsapp, games, lockscreen, calendar, etc.).
Options
If I understand correctly, you're wanting to show a UIView on top of another application's window. In the app sandbox, you are only allowed access to your own application's window. Jailbreaking, however, will allow you to do this, but it's not exactly simple.
In order to show a view on top of applications, you have three choices. Which option you choose depends on what you're trying to do.
Inject your code into third-party applications
Inject your code into SpringBoard
Use a combination of methods 1 and 2.
Option 1
If you choose to go with this route, your code will be running inside each third-party application. This allows you to modify the view hierarchy of the application to show your own window or even modify existing ones. Since you're code is running in the application, you can obtain the key window by simply calling:
[[UIApplication sharedApplication] keyWindow]
Option 2
If you choose this option, your code will be running regardless of what application is open. By obtaining the main window, you can show UI over anything, including system alerts. I've posted an example of this to GitHub at rpendleton/tutorials/so-26032688. The example shows an alert anytime the user takes their phone out of silent. The code to retrieve SpringBoard's window is:
[[NSClassFromString(#"SBUIController") sharedInstance] window]
Option 3
The third option, and the one you'll likely end up using, is a combination of both options 1 and 2. In this scenario, you'll inject your code into third-party applications, and then communicate with SpringBoard to decide what needs to be done. Typically, your application would communicate with SpringBoard, then SpringBoard can relay that information to the desired application. You may be able to communicate directly between your application and a third party application, but I haven't tried that.
Communication
In order to communicate between your application and SpringBoard / other third-party applications, you'll need to use a messaging system. An easy way to do this communication is via a open source library called RocketBootstrap.
Screenshots
The screenshot on the left is from the example I posted on GitHub, and the screenshot on the right is from one of my tweaks AppScan. Although I'm presenting an alert in both, you can show whatever view you desire.
try getting window of AppDelegate like this
UIWindow *window = ((AppDelegate*)[UIApplication sharedApplication].delegate).window;
And then access window's last object like this
[[window subviews] objectAtIndex:0];
or like this
[[window subviews]lastObject];
If you want to addsubview to it
[[[window subviews] objectAtIndex:0] addSubview:view];
Reading the question and the comments this is what you're looking for...I think, not the most detailed question I saw:
UIWindow *window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
window.rootViewController = self;
window.windowLevel = [[UIApplication sharedApplication] keyWindow].windowLevel + 1;
[window makeKeyAndVisible];
You want to use this as part of the view controller that you want on top.
You question is not totally clear, can you explain why you need to do that?
By the way most probably what you need is the key window first, as stated in the doc:
The key window is the one that is designated to receive keyboard and
other non-touch related events. Only one window at a time may be the
key window.
What you can do is ask for the application current key window:
NSArray * array = [[UIApplication sharedApplication] windows];
Iterate over that array to find the key window and then check for its subviews:
UIView * topView = [[window subviews]lastObject]
If you are looking to a way for emulate an alert view, You should create your own UIWindow and later ad your view controller that handles the "alert" as a rootViewController and make it" key and visible".
Something like that :
UIWindow *alertWindow = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
alertWindow.rootViewController = [[AlertViewController alloc] initWithXibNamed:#"AlertXib"];
alertWindow.windowLevel = UIWindowLevelAlert;
[alertWindow makeKeyAndVisible];
And when you want to dismiss just set the rootViewController to nil and make the window hidden.
Using the root view controller approach helps into avoid messing with rotation corrections. Even if in iOS8 the rotates.
I've found a good reference here.

applicationWillResignActive called by iOS alerts too. How to avoid this?

I use applicationWillResignActive to display the splash image when my app is in background (see code-snippet). Reason: I don't want private data of the app be visible when my app is in background on iOS 7 and the user presses the Home button twice.
splashWindow = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
splashWindow.windowLevel = UIWindowLevelAlert;
[splashWindow addSubview:splashViewController.view];
[splashWindow makeKeyAndVisible];
The problem is that applicationWillResignActive is also fired when iOS shows an alert because some certificate is about to expire. How can I fix this? Do I need to take another approach to display the splash image in background?
Thanks for any advice
You could also use the applicationWillEnterBackground to open a blank screen/your splash image and switch back to your normal screen with applicationWillEnterForeground.
Fixed: I could not change the iOS behaviour as described but I used:
[self.window addSubview:splashViewController.view];
instead of the code-snippet above. The iOS alert still makes the splash appear but I hide it again in applicationDidBecomeActive with [splashViewController.view removeFromSuperview];
The splash now disappears when the alert is answered with OK or Cancel.

calling a second view in iPad app

I am trying to adapt an existing application to an iPad app. The application has a main view that calls View2 that is in "View2.xib". Everything has been working well, until I entered the following:
if(!view2Controller)
{
view2Controller = [[View2Controller alloc] initWithWindowNibName:#"View2"];
}
[view2Controller showWindow:self];
This works in my original Cocoa program, but in the iPad application it is currently returning a warning: "Thread1: Program received signal "SIGBRT" While working with it, I've also received a message Method -initWithWindowNibName not found.
Similarly, I have the same problem with the method showWindow.
I wonder how it is that this problem shows up when I try to convert it to an iPad app.
I've run out of ideas to check and would appreciate some assistance.
You will need to change it to the following
if(!view2Controller)
{
view2Controller = [[UIViewController alloc] initWithNibName:#"View2" bundle:nil]
}
//If you are in a view controller use
[self presentModalViewController:view2Controller animated:YES];

iPad open a modalViewController at application launch

here is my problem: I have an iPad application based on a SplitViewController. When I launch the application, since it always starts in portrait mode, only the Detail pane is shown. All right. I want now open a modalViewController at the application launch for login purpose, but I am not able to find out the right way. I grasp on the web the following code:
SampleModalViewController *sampleView = [[[SampleModalViewController alloc] init] autorelease];
[sampleView setModalTransitionStyle:UIModalTransitionStylePartialCurl];
[self presentModalViewController:sampleView animated:YES];
and it runs nicely, but where do I have to place it in order to have the modal controller displayed at startup? I tried to override viewDidLoad in the DetailViewController, but it does not work.
Thanks for your help!
Roberto
They suggested me an answer:
http://forums.macrumors.com/showthread.php?t=1097839

Resources