I have discovered a situation that causes dismissViewController:animated:completion to not dismiss the view controller that has been presented. While it does dismiss on iPad running iOS 8, it doesn't dismiss on iPad running iOS 7.1. I've tried self, self.presentingViewController, and self.presentedViewController - all do nothing. I've tried it with Xcode 6.0 and 6.1 beta. While I do believe this is a bug, what can be done to work around it and force dismiss that view controller, ensuring it will work for iPad running iOS 7 and 8 (presented as a popover), and iPhone running iOS 7 and 8 (presented full screen)?
I have created a very simple project you may use to try this: Xcode project zip.
Project setup:
Universal storyboard targeted to iOS 7+
Implement Popover Presentation segue
Implement ability to dismiss popover inside that popover
To encounter the unexpected behavior:
Open the provided Xcode project
Run the app on iPad iOS 7 Simulator
Tap the top cell to present the popover
Tap the cell in the popover to dismiss it
The problem is in the way you try to handle the popover. To close the popover you should use the dismissPopoverAnimated method instead of dismissViewControllerAnimated.
I think you will have to make more work to complete your task for targeting both iOS versions. The root view controller should have some property to store the created popover with PoppedUpTVC as popover content and the PoppedUpTVC has to ask the root view controller to perform dismissPopoverAnimated method on the stored popover to close it.
To get a reference to the popover, try this in prepareForSegue:
if ([segue isKindOfClass:[UIStoryboardPopoverSegue class]]) {
UIStoryboardPopoverSegue *popoverSegue = (UIStoryboardPopoverSegue *)segue;
yourDestViewController.propertyToStorePopover = popoverSegue.popoverController;
}
Related
I have an app with a navigation view controller and once a cell is tapped on, a screen is pushed on top of it. However, when testing this app on a simulator and on multiple devices, the push segue somehow turns into a modal segue. These pictures will show a gist of what is happening:
Table View:
What is supposed to happen (Show segue):
What happens instead (Modal segue):
I am running this on an iOS simulator but for my app the result is the same. I have seen people post about this issue taking place on iOS 7, but is this supposed to happen with iOS 9?? Please help.
Thanks!
I have found a solution. It appears, that now, in Xcode 7, you should make a segue not to navigation controller, but to your viewController directly, in order to achieve desired push segue.
I have very strange problem on ios simulator 7.1 with auto layout but on ios 8 everything works fine.
On ios simulator 7.1 when new "View Controller" was presented through segue its content becomes layout incorrectly and sometimes even moves.
Demo code on github:
https://github.com/Misterio26/iOS-7-Simulator-Bug-demo
This demo uses only interface builder, there's no hand code at all, that is why I very surprised about this bug.
To reproduce:
use xCode 6
run with ios simulator (7.1)
press "Works", you will see a test screen that is aligned correctly (sometimes not), then press "Back"
press "Bug", after screen appearance you will notice some ui movement and incorrect alignment (sometimes it shows constraints error in console log)
I log window.hasAmbiguousLayout in viewDidAppear, and it print "false" for iOS 8 and "true" for iOS 7. Looks like iOS7 creates wrong constraints for presenting view controller. I used "po [[UIWindow keyWindow] _autolayoutTrace];" and it confirmed my suggestion.
I can't belive that only I have noticed this problem.
Can someone help me to know:
Is it simulator bug or it happens on real device too? (I don't have ios 7 device, just 8, and apple doesn't allow to downgrade ios)
Or maybe it can be fixed?
Or you can only try to reproduce that window.hasAmbiguousLayout becomes "true" after segue (I think that it's very dangerous bug):
create new iOS project in XCode6
in IB create new View Controller with one button
in IB create second View Controller with any content
in IB create "show" segue from button to second view controller (command + drag from button to second view controller)
in CODE create new class #interface CustomViewController : UIViewController
in CODE add to CustomViewController
- (void)viewDidAppear:(BOOL)animated {
UIWindow* window = [UIApplication sharedApplication].keyWindow;
NSLog(#"viewDidAppear hasAmbiguousLayout %#", ([window hasAmbiguousLayout] ? #"true" : #"false"));
}
in IB apply class CustomViewController to second view controller
run on ios 8 and you will see "viewDidAppear hasAmbiguousLayout false"
run on ios simulator 7.1 and you'll see "viewDidAppear hasAmbiguousLayout true"
I think it's very dangerous behavior.
I use storyboards, no navigation bar or tab bar. I'm using 2 view controllers and 2 storyboards for my app. ViewController has intro of game and ViewControllerTWO has actual game. I'm using ViewController and ViewControllerTWO for iPhone 4s and iPhone 5,5s.
ONLY when I load the iPhone 4s simulator, in the Debug Area, Xcode tells me "Warning: Attempt to present "GKHostedAuthenticateViewController: 0x8989e7e0 on ViewControllerTWO: 0x78974xc0 whose view is not in the window hierarchy!"
Also, when I plug in my iPhone 4s device, I don't get this message, it only gets this message when i'm using simulator for iPhone4s.
What does this mean? What's Xcode want with ViewControllerTWO?
Try to perform your segue in -viewDidAppear:. The view controller can't present anything before its loaded into the main window.
I'm in the process of moving from hard-coded layouts to the new universal storyboard system available in Xcode 6. It's great to be able to create one storyboard that, through the magic of auto-layout, will work on both the iPhone and the iPad. And my understanding is that universal storyboards are backwards-compatible with iOS 7.
However, I'm running into a problem using popover segues. On iOS 8, the new 'Present as Popover' segue will display as a popover on an iPad interface and as a modal view controller on an iPhone interface. This is exactly the behavior I want, but when I run my universal storyboard on iOS 7, the app crashes whenever I attempt a popover segue. Here's the error message I get:
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason:
'-[UIPopoverController initWithContentViewController:] called when not
running under UIUserInterfaceIdiomPad.'
This is a bit annoying, as I don't want to have to resort to separate storyboards for each UI idiom.
It looks like these are my choices:
Create a subclass of UIStoryboardSegue that will show a popover on iPad and a modal view on iPhone. This requires manually changing the class of all popover segues in my app.
Create two segues out of every bar button item, table cell, etc. - one that's a pure 'Popover' segue and one that's a pure 'Modal' segue. In this case, I'll be unable to just control-drag to the next screen and will have to create custom action methods that will invoke the right segue based on the current UI idiom.
Abandon universal storyboards and create device-specific storyboards until I can require iOS 8 from my users.
None of these are great alternatives, so I was wondering: do I have any other options? Am I missing any problems with my proposed solutions?
Xcode 6 supports unified storyboards. A storyboard can add or remove views and layout constraints based on the size class that the view controller is displayed in. Rather than maintaining two separate (but similar) storyboards, you can make a single storyboard for multiple size classes.
But Size classes are based on UITraitCollection which is supported on iOS8. That's why it's crashing on iOS7.
I ended up making a modal segue and checking in code to see if it was on a iPhone with iOS 7. I then use performWithSegue to pick which segue should be taken. iOS 8 can handle the popover code but iOS 7 has issues.
Seems Like You are trying to present your view modally if device is iPhone and as Popover if the device is iPad..
To produce that the easiest way would be to check the InterfaceIdiom when the event occurs(like button click) and conditionally using appropriate approach.
-(IBAction)btnClicked:(id)sender{
if([[UIDevice currentDevice] userInterfaceIdiom]==UIUserInterfaceIdiomPad){
//your popover code..
}else{
//your present modaly code...
}
}
I have a strange behavior of Split View Controller in iOS 5.0 and iOS 6.0 iPad simulators. I created Master View Detail template in Xcode and set deployment targets everywhere to 5.0. I switched Autolayout off and set orientation to landscape only.
My app works as follows - Split View Controller is my root VC and because I need to display login first I use
- (void)viewWillAppear:(BOOL)animated {
[self presentModalViewController:[self.storyboard instantiateViewControllerWithIdentifier:#"loginVC"] animated:NO];
}
in the MasterViewController. Everything runs smoothly on iOS 6 simulator, but the 5.0 just won't display the login VC and shows the rest in portrait mode, but turned to landscape. Picture attached below.
Anbody knows what could be wrong?