setStatusBarOrientation causing problems in iOS8 - iphone

I'm having real problems with my apps under iOS8. I've made a bunch of OpenGL based apps, which don't need the iOS to handle the orientation. It's all handled within the OpenGL section. But I do use setStatusBarOrientation to make sure any dialogs/keyboards etc that pop up line up with everything else. I'm creating my window and view programatically or in a xib, I've never needed to use a storyboard (in case thats relevant?)
It's all been perfect, til iOS 8 came along.
Now it seems that setStatusBarOrientation isn't behaving properly at all. It's either not changing anything, or it's rotating "something" that stops touches being recorded on half the screen. It's as if the window is being rotated within itself, but visually nothing changes, just the touches are effected.
It's hard to explain, and makes no sense.
But my question is: How do you set the status bar orientation in iOS8? And how do you do it without destroying everything else that works in previous iOS versions?

Set iOS7.1 as your Base SDK, and it'll work fine on iOS8, without all these strange bugs.
http://objcsharp.wordpress.com/2014/09/21/how-to-get-back-the-ios-7-sdk-after-upgrading-to-xcode-6/

found this
if ([UIViewController class]) // iOS8 has this class only
{
[[UIDevice currentDevice] setValue:[NSNumber numberWithInteger:UIDeviceOrientationPortrait] forKey:#"orientation"];
}
found here:
http://blog.lessfun.com/blog/2014/09/24/ios8-issue-keyboard-orientation-and-idletimerdisabled-not-working/
seems to work

Related

Gestures handled identically in iPhone and iPad

I'm working on an app right now where a tap will be handled identically on the iPhone as on the iPad. I don't have an iPhone, so I'm using the simulator to test for now. I thought I could simply click with my mouse on the screen if the simulator to simulate taps, but that doesn't seem to work.
So I had the thought that maybe the problem was that I started with iPad and created the iPhone interface later (although the project itself was generic from the start).
I copied the gesture recognizers (tap and two swipes) from the storyboard for the iPad and pasted them into the storyboard for the iPhone. I didn't think this was going to work, but I was hopeful that's all I would have to do. In any case, it seems like the same code should be able to be linked from both storyborad gesture recognizers.
When that didn't work, I hooked up the iPhone gesture recognizers using Control-drag just like I did with the iPad. This created new methods. Since the same code could be used, I thought I'd simply call the other:
- (IBAction)tapIphone:(UITapGestureRecognizer *)sender {
[self tapIpad:sender];
}
- (IBAction)tapIpad:(UITapGestureRecognizer *)sender {
omitted code
}
That didn't work either. So next I tried copy/pasting the code from the iPad method to the iPhone method. It still didn't work.
So now I'm wondering if maybe I don't know how to test taps properly on the iPhone simulator. What else could I have missed?
It seems clear that the tapIphone method is not being called at all. You can work that out by adding #NSLog("tapIphone") in the method, see if it logs. In fact put these lines into their respective methods:
#NSLog("tapIphone");
#NSLog("tapIpad");
If tapIphone WAS getting called and the tapIpad method IS in the same class, the expected behaviour should have occurred.
Your first intuition, to copy and paste items from one storyboard to the other, is fine. However you lose all IBAction / IBOutlet connections when you do this (they don't carry over their links to and from the old storyboard, they just go), so you have to rewire them each time. Which is a bit of a pain when you are trying to adapt interface from one device for another. This does not mean that you have to create new code - it just means you have to CRTL-drag from each storyboard item onto the existing IBAction code item you want to reconnect to (you can achieve the same result by CTRL-dragging from the storyboard item to the relevant controlView storyboard icon, which will present you with a list of optional IBAction items to connect to). Same goes for any IBOutlet connections you want to replicate.
This is not an issue with the simulator, you just need to tweak your understanding of storyboard wiring.
I would not recommend your suggestion of separate IBAction methods as a way to handle different behaviours on different devices. This will lead to more wiring complexity which is irritating to debug. There are better ways to do that, for example by checking environment capabilities or using:
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
//iPhone code goes here
} else {
//ipad code goes here
}

iOS 5 issues: Navigation bar clipped after dismissing modal

I have a nice little app on the app store that does pretty well for itself. Life was great until iOS 5 came to town. Now, I have a number of issues with my app that I have no way of fixing because I have no clue what is going on, because I feel that they are iOS 5 issues, not mine.
Was there an iOS 5 conversion manual I missed? Or did they just change everything for fun, and want us to figure out where all the easter eggs were?
Here is another issue I am experiencing (that I have wasted so much time trying to fix), that DON'T EXIST AT ALL when I simply say that I want to run the app in good ol' 4.2:
Modal view
My app is a simple reader app. I have a book reading view that displays text with a UIWebView. One of the features I have been working on involves the ability to take notes as you read. This is achieved by hitting a button, and presenting a modal view. Yes, a modal view. The most simple pre- iOS 5 thing you could possibly do. Now, when I dismiss my modal view, just by hitting cancel, and simply dismiss the view, when I get back to my reader view, the navigation bar at the top is pushed up half way off the screen! This doesn't happen in 4.2, but there it is in iOS 5!
What can I do to get this issue resolved?
Thanks for your help.
Ok, I was just able to figure out what in the blazes was going on. I had the shouldAutorotateToInterfaceOrientation value set to a BOOL variable, so that when the modalView was coming back, it didn't know the state/size of the status bar. Fixed that, and the problem disappeared.
I have the feeling it has something to do with the way you present and dismissing the modalview. Apple introduced a new method to present views. May you try using theses instead of the old ones and see if it fixes your problem.
So here is what you do:
change this method:
presentModalViewController:animated:
into the new preferred method introduced with iOS 5:
presentViewController:animated:completion:
Depending if you are using dismissModalViewControllerAnimated:to dismiss your view, change it into dismissViewControllerAnimated:completion.
This methods also have completion handler which is very useful to do some extra work after the view has been presented/dismissed. Maybe that also helps with your other issue. Let me know if that might helped.
A major change in iOS 5 is that the navigationController property of UIViewController is no longer set for modal views. Instead, there is a new (not present in iOS 4) parentViewController property. So where you're using navigationController in a modal view you need to change the logic to something like:
UIViewController* parent;
if ([self respondsToSelector:#selector(parentViewController)]) {
parent = self.parentViewController;
}
else {
parent = self.navigationController;
}
(That's from memory, so I can't guarantee that every t is dotted and every i crossed.)
I was seeing this same clipping problem.
I found out that the reason for my issue was that I set the content size within the modal dialog (something I did for my iPad layout), so removing these two lines seemed to fix the issue:
CGSize size = CGSizeMake(320, 480);
self.contentSizeForViewInPopover = size;
I thought the problem was fixed but it wasn't. After reviewing the code some more, cleaning the build, and retesting it turned out to be a shouldAutorotateToInterfaceOrientation which would return NO for all orientations, for a brief amount of time (flag == NO) while the app is loading (root controller). You want to at least return YES to one orientation like so:
- (BOOL) shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
{
return !self.flag ? UIInterfaceOrientationPortrait == toInterfaceOrientation : YES;
}

iOS - status bar randomly turns solid black

Developing an iPhone app.
I've got a really strange problem where, every once in a while, the status bar at the top of my app screen will turn solid black. Not like the black version of the status bar, but like a solid black rectangle with NO text/icons. It's very rare, but usually seems to occur after returning to the app via multi-tasking or from a locked device (the app has been running in the background). I've seen it occur on both 3GS and iPhone4. Here's a screenshot:
I can never reproduce it when trying, it just seems to eventually happen at some point (sometimes it will go for days without happening).
Once it does occur, the app seems to continue functioning fine, even with the status bar gone, except for when I do one specific action in the app which will cause everything to freeze up all the sudden (the app doesn't crash, but everything on screen is frozen and non-interactive). Without explaining the design in detail, the specific action that causes it to freeze up (after the bug appears) is performing a simple upload in the background to a SQL database. Resetting the app is the only way to fix the problem once the black status bar appears.
Anyone else ever experienced this? I can't find a single thread anywhere explaining similar behavior, and it's driving me nuts.
It happened once in my app when I called a drawing method in my custom subclass of UIView instance right before I added it as a subview to parent view.
The solution was apparently easy: add it as a subview first before sending/calling any custom drawing methods.
Examples:
CustomView *aView = [[CustomView alloc] init];
[aView drawSomething];
[self.view addSubview:aView]; //wrong approach
[aView release];
Should be:
CustomView *aView = [[CustomView alloc] init];
[self.view addSubview:aView];
[aView release];
[aView drawSomething];
The screenshot is missing, but what you describe sounds as though you've incorrectly implemented the use of Apple's built-in view controllers.
Both UINavigationController and UITabBarController will automagically shift all the content inside them down by 20-pixels, if they detect there is "supposed" to be a statusbar on screen at the moment.
My guess is that you have some code that is removing the statusbar, but which is kicking-in after the Apple code has already detected it and shifted everything down to accomodate.
The "fix" is to re-read the docs on Apple's classes very carefully and use them as Apple dictates (usually, people use them in ways that seem sensible - e.g. embedding them inside other views - but which Apple has expressly declared are unsupported. Sadly those classes from Apple are very fragile)
Are you holding a reference to a QLPreviewController instance? I was able to solve this problem in my app by creating a new autoreleased QLPreviewController whenever I need to display a file modally, as opposed to reusing the same instance over and over again.
I had a similar problem, which I described in this question here
If you have any, try removing any CGRect frame created by reference to:
[UIScreen mainScreen].applicationFrame]
and instead create the frame using a more manual definition. If that works, you can decide how to proceed from that point.

shouldAutorotateToInterfaceOrientation doesn't work on first launch after fresh app install

When the app I'm working on is installed either via Ad-Hoc thru iTunes or built directly to the device, upon launching for the first time, the only view controller in my app that responds to orientation changes doesn't receive calls to shouldAutorotateToInterfaceOrientation: with a landscape argument passed in; debugging shows that it's only being called for portrait. Every subsequent launch behaves as I would expect - that is, there are calls to shouldAutorotateToInterfaceOrientation: made both with landscape and portrait arguments. This exact behavior can be seen in the iPhone simulator, on the iPhone and on the iPod touch.
So my question is: why would orientation notifications be different for the first launch of an app than they would be for every subsequent launch? Am I mistaken in believing that I have no control over orientation changes beyond responding to shouldAutorotateToInterfaceOrientation:?
Inside the ViewController in question:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
{
return YES;
}
and inside of viewDidLoad and viewDidUnload I've got (respectively):
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
and
[[UIDevice currentDevice] endGeneratingDeviceOrientationNotifications];
Update July 6, 2010:
Still no luck solving the problem. I dropped the issue for a little while and came back to it and am still seeing the problem under completely different circumstances. Anyone?
Update July 13, 2010:
From Apple's View Controller Programming Guide:
"...the window object does much of the work associated with changing the current orientation. [...] Specifically, it works with the view controller whose root view was most recently added to, or presented in, the window. In other words, the window object works only with the frontmost view controller whose view was displayed..."
I'm adding the root view controller to the window differently on the first launch compared to every subsequent launch, so I thought maybe it had something to do with this. I have yet to trace anything back to here though...just a thought.
This thing has had around 175 views at the time of this update...no one has even the most far out obscure suggestion? Come on, throw something out there. I'm willing to entertain any guesses or suggestions at this point. I don't care if it's stupidly obscure or potentially irrelevant.
Never did solve this problem - I left the company where I encountered it before I had a chance to. However, I had a pretty good lead on it by the time I left. I contacted Apple DTS about the issue and they noted that for autorotation to work properly, all ViewControllers in the view stack related to autorotation must call the super methods in the method implementations (i.e. calling [super viewDidLoad] from within the ViewController's viewDidLoad). I don't remember which methods they cited exactly, but it's probably worth a shot to ensure you're properly calling super where appropriate.
[EDIT] If someone can confirm this, I'll mark it as the accepted answer. Thanks!
also make sure you set:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Return YES for supported orientations
return YES;}
in ALL ViewControllers.m in your app, not just one you're working on (if you have more than one). I was struggling trying to get it going for the FirstViewController, but it wouldn't work no matter what. As soon as I added the above code to all four view controllers, it started to work just fine (in all four)
I had a similar problem - the UIDevice.h header lists endGeneratingDeviceOrientationNotifications and beginGeneratingDeviceOrientationNotifications as "nestable." It turns out I had unbalanced calls to these methods.
I solved this quickly with the following change to beginGeneratingDeviceOrientationNotifications:
if (![[UIDevice currentDevice] isGeneratingDeviceOrientationNotifications])
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];

Single-Stage vs Two-Stage Animation for iPhone Apps?

What are single-state and two-stage animation for rotating an iPhone window?
This is the "error" message I get in the Debugger Console (nothing crashes):
Using two-stage rotation animation. To use the smoother single-stage animation, this application must remove two-stage method implementations.
I was working through the book "Beginning iPhone Development: Exploring the iPhone SDK" by Apress (Dave Mark, Jeff LaMarche) on the Swap Project.
Everything is explained in the UIViewController Class Reference. Especially check out the View Rotation section near the top.
From the reference:
Handling View Rotations
By default, the UIViewController class
displays views in portrait mode only.
To support additional orientations,
you must override the
shouldAutorotateToInterfaceOrientation:
method and return YES for any
orientations your subclass supports.
If the autoresizing properties of your
views are configured correctly, that
may be all you have to do. However,
the UIViewController class provides
additional hooks for you to implement
additional behaviors as needed.
To temporarily turn off features that
are not needed or might otherwise
cause problems during the orientation
change, you can override the
willRotateToInterfaceOrientation:duration:
method and perform the needed actions
there. You can then override the
didRotateFromInterfaceOrientation:
method and use it to reenable those
features once the orientation change
is complete.
If you want to perform custom
animations during an orientation
change, you can do so in one of two
ways. Orientation changes used to
occur in two steps, with notifications
occurring at the beginning, middle,
and end points of the rotation.
However, in iPhone OS 3.0, support was
added for performing orientation
changes in one step. Using a one-step
orientation change tends to be faster
than the older two-step process and is
generally recommended for any new
code.
To add animations for a one-step
orientation change, override the
willAnimateRotationToInterfaceOrientation:duration:
method and perform your animations
there. To use the older two-step
method, override one or both of the
willAnimateFirstHalfOfRotationToInterfaceOrientation:duration:
and
willAnimateSecondHalfOfRotationFromInterfaceOrientation:duration:
methods to configure your animations
before each step. You must choose only
one technique and override just the
methods associated with that
technique. If you override either
method associated with the two-step
technique, the view controller uses
that technique by default.
I have found the culprit in my case to be the UIImagePickerController (I also do not override any rotation animation):
[self presentModalViewController:imagePicker animated:YES];
Replacing imagePicker with a generic UIViewController doesn't generate any warnings.
I changed from willAnimateFirstHalfOfRotationToInterfaceOrientation:duration: method to willAnimateRotationToInterfaceOrientation:duration: method and warning gone.
Thanks.
Ed Marty's answer is the correct one. The reason it will happen if you are not overriding any of the rotation animation is probably that you reply "YES" to shouldAutorotate.. for some view. If you do not implement rotation at all, then you should just not override the shouldAutorotate.. method. If you do override that method, then just override the single step rotation method as well and pass it along to the super.
If you're using iOS 4 and you're getting this warning, I found a way to get rid of it. In your info.plist, there is an item called "Supported interface orientations." Select which orientations your application supports and two-stage warnings will go away when bringing up the imagePicker.
#plumiscles answer didn't quite work for me - there was no item called 'Supported Interface Orientations', probably b/c it is an old project. But you can get the same effect by editing the .plist file directly and adding this:
<key>UIInterfaceOrientation</key>
<string>UIInterfaceOrientationPortrait</string>
Need to add UIImagePickerController as a subview to solve this error
[self.view addSubview:picker.view];
[self presentModalViewController:picker animated:NO];
I've had this issue after creating a tabbarcontroller with no view controllers inside (no tabs), this warning disappeared once I attached at least one view controller to it.
I wasn't over riding any of those two-step functions, but I was calling my own function when I received orientationChanged notifications, and I had this line of code in it. Commenting it out got rid of the warning and allowed the auto rotate to work properly. Auto rotate still worked with this line of code until iOS 4.2, then it broke completely. Spent a lot of time looking for why the built in autoRotate stopped working in 4.2. Maybe this will help someone else.
Commented out this line to make it work:
[[UIApplication sharedApplication] setStatusBarOrientation:currentOrientation animated:YES];
I've delete from plist "Supported interface orientations" row and warning disappears.
I just had the same problem. In my case was a silly mistake that I'm putting here just in case anyone else falls into that same issue.
In my tabbed app I remove one of the original ViewControllers and added a new one with Storyboard to create a "Settings" section.
This new VC had to be a table view VC and even I designed, compiled and run it without a problem, when I changed the orientation of the app I kept getting this “Using two-stage rotation animation” error.
My problem was that I forgot to change in the original .h file interface "UIViewController" for "UITableViewController".
Once this was done I changed on the Storyboard identity badge the class from the general value to my SettingsViewController and that was the end of it.
I hope it can help someone else. It took me a while to get to bottom of this.
Cheers,