iOS app crashing after setting UIWindow rootViewController in iOS 9 - ios

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.

Related

How to present iOS Keyboard extension using presentViewController

My goal is to present the iOS Keyboard with the method presentViewController:animated:completion whenever the keyboard has successfully instantiated, taking advantage of the smooth upward animation.
Some very brief background: the keyboard extension project is written in Objective-C, with KeyboardViewController.h/.m handling the logic and some basic view layout from a inputView.xib.
Based on this SO question, several of the the answers suggested using the approach of calling presentViewController from [UIApplication sharedApplication].keyWindow.rootViewController. The problem is, as this is an iOS extension, when I try to replicate this method, I get the error that sharedApplication is not available. I was wondering if a workaround exists where I could present the Keyboard with the method presentViewController, either somehow via itself or via a super? In my current attempts, calling [self presentViewController: self...] causes an exception.
Much appreciated!
It can't be done.
One can actually acquire a reference to [UIApplication sharedApplication] easily, the most straightforward (though liable to get you rejected in App Store review) would be:
Class appClass = NSClassFromString(#"UIApplication");
id app = [appClass performSelector:#selector(sharedApplication)];
Running on the iPhone 5 simulator, [app keyWindow] returns nil when called from the principal input view controller's viewDidAppear: method.
[UIApplication windows], however, does not, so we could try
[[[app windows].firstObject rootViewController] presentViewController:self
animated:YES
completion:nil];
...but it just throws an exception:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Application tried to present
modally an active controller .'
Walking the view hierarchy starting from UIApplication windows] reveals an interesting fact: the window of our UIInputViewController isn't in this window hierarchy. self.view.window returns a separate _UIHostedWindow with no superView.
Furthermore, There is no variation across apps of the addresses in memory of windows returned from [UIApplication sharedApplication].
Conclusion: the UIApplication we get from sharedApplication is the one for our process, not for the host process. Presenting on views and windows it owns therefore is pointless, because its views aren't visible to the user.

Warning: Attempt to dismiss from view controller <ViewController> while a presentation or dismiss is in progress

I´m new to Xcode but I keep on making some small apps to learn. I have run into a problem that only sometimes occurs with the message "Warning: Attempt to dismiss from view controller while a presentation or dismiss is in progress!" and the app then crash.
I have searched around and found some possible answers but no luck for me yet.
My code for back is:
- (IBAction)Back {
UIViewController *back = [[UIViewController alloc] initWithNibName:nil bundle:nil];
[self presentViewController:back animated:NO completion:NULL];
I understand that the problem is that I try to go from one viewcontroller to another before the presentation of the viewcontroller is done.
The strangest thing is that this sometimes isn´t any problem and the app works flawlessly.
Ok, I think you have trouble with the concept of navigation in iOS. First take a look at iOS Human Interface Guidelines: Navigation, and then read: Navigate with UINavigationController in iOS7 (don't worry about ios 7 or 8, they're both similar)
Overall, I really recommend watching Stanford's Developing iOS 7 apps for iPhone or following the newest one: Developing iOS 8 Apps with Swift to learn!

presentViewController doesn't work on iOS7, app hangs

I'm using GCD to make sure this happens on the main thread, but even that doesn't fix the issue.
- (void)showCat:(NSNotification *)notification {
dispatch_async(dispatch_get_main_queue(), ^{
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
UINavigationController *navVC = [storyboard instantiateViewControllerWithIdentifier:#"Cat"];
[self presentViewController:navVC animated:YES completion:^{
//this never happens on iOS7
}];
});
}
navVC is not nil.
Works fine on iOS8. On iOS7 the app just hangs. Memory usage continuously goes up until it crashes due to memory pressure.
What else could be the cause of this? presentViewController works fine in other areas of the app. This code is called when a notification is received.
Actually turned out there was some recursive code in viewDidLayoutSubviews of the presented view controller. Thanks to #matt for the tip. Not sure why this isn't also an issue in iOS8, but nevertheless the problem is fixed.
Goes to show that actually offering advice even if you don't have the entire code base of the project in front of you can still be helpful, rather than simply downvoting from your high horse.

"Application windows are expected..." warning, but app runs fine

I'm getting the following error in my console upon launching my iPad-based iOS app:
"Application windows are expected to have a root view controller at the end of application launch"
I've looked at answers to other questions that reference this error, but none of them seem to be my particular issue.
In fact, the only symptom I have that there is a problem at all is the message in the console at app launch. My app seems to run fine and performs exactly as I desire.
I'm using a single storyboard file (Main.storyboard) to generate my app's UI (with a couple of XIB files for custom views). All of my UIViewController subclass UI is contained in the single storyboard. This storyboard is specified as the 'Main Interface' in my 'Deployment Info'.
Here is the code in my AppDelegate (I've removed some non-UI-based app initialization code):
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
MSSAppSingleton *app = [MSSAppSingleton singleton];
// Other, non-UI code, like TestFlight, etc.
UISplitViewController *split = (UISplitViewController *)self.window.rootViewController;
UINavigationController *leftNavVc = split.viewControllers[0];
UINavigationController *rightNavVc = split.viewControllers[1];
app.containerSplitViewController = split;
app.leftRoot = leftNavVc.viewControllers[0];
app.rightRoot = rightNavVc.viewControllers[0];
return YES;
}
This code appears to run without a problem. I'm grabbing these references for later UI manipulation, and all of that is working as desired. Every single one of the lines of code above runs as I would expect. self.window has a valid reference. self.window.rootViewController does, too.
So, this isn't really a "problem", except I follow the philosophy of "treat every warning as an error" and would love to get this warning to disappear. Has anyone else seen this? I'm using Xcode 5.0.2 and running the iPad 7.0.3 simulator.
MSSAppSingleton *app = [MSSAppSingleton singleton];
is supposed to be called before
app.containerSplitViewController = split;
Xcode likes it when you set the root view controller
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
[self.window setRootViewController: someViewController];
[self.window makeKeyAndVisible];
I don't use storyboards myself though.
You may need to set the root instead of just getting it and then applying things to it to make it happy.

How to call a view controller from AppDelegate in 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.

Resources