iOS6 rotate methods not called when launching in landscape - objective-c

Let me start off by saying I'm not having a problem when rotating views in iOS6 after the app is open. This issue is only happening for me when the app is launched for the first time while in landscape. The new shouldAutorotate and supportedInterfaceOrientations methods are both called when launched, however none of the rotation methods are called, like willRotateToInterfaceOrientation:duration:. (shouldAutorotate is always returning YES, and supportedInterfaceOrientations is always returning UIInterfaceOrientationMaskAll)
In iOS5, the 'first' orientation to landscape on launch was taken care of automatically. Is there an explanation for why the device wouldn't call this first landscape rotation in iOS6? (The view controller I'm checking is the root controller of the window/app delegate).
Thanks in advance for any help with and insight into this.

I suppose that since the interface is not actually rotating, that the method isn't being called.
If you want to do some setup based on the orientation, have you thought of using the view controller's intefaceOrientation property?

You should now use the viewWillLayoutSubviews method and not willRotateToInterfaceOrientation:duration:. The reason is because willRotateToInterfaceOrientation:duration: is not guaranteed to be called in a number of situations.
This is stated in the iOS6 release notes among other places.

Related

Autorotation in ios 5 vs. ios 6 issues

I have an iPad app that must support iOS 5.0 and later. I have a bug that behaves differently in 5.0/5.1 than it does in 6.0. The issue is a view controller in a tabbarcontroller that pushes a modal view, which in turn pushes a full-screen view via navigationController. The problem is, when in the full-screen view, if the iPad is rotated, the underlying viewcontroller (one in the tabbarcontroller) doesn't rotate. Now let me break down the differences in iOS versions:
First of all, this viewController in question implements shouldAutoRotateToInterfaceOrientation (returns YES) as well as willRotateToInterfaceOrientation and willAnimateRotationToInterfaceOrientation.
In iOS 6.0, I noticed that the rotation methods (willRotate... & willAnimate...) were not being called, so I registered it to receive the UIDeviceOrientationDidChangeNotification notification and execute the code from the two Rotate methods if I received that notification and the other methods hadn't executed. That fixed the issue in iOS 6.0.
Problem is, in 5.0/5.1 the rotation methods (willRotate... & willAnimate...) ARE being executed, but the view is not rotating. If the "full-screen view" is not presented over top of this view controller and the iPad is rotated, these two methods execute and the views rotate accordingly.
Please help. Thanks in advance.
Things I've tried other than that stated above.
I've tried checking the UIDeviceOrientation and converting it to a UIInterfaceOrientation and calling [self shouldAutorotateToInterfaceOrientation:xxx]; The view still displays wrong.
When the two rotation methods are being executed, do the CAAffineTransformation for your view. when you are back to normal, again do the same with -90 degree.
https://developer.apple.com/library/ios/#documentation/GraphicsImaging/Reference/CGAffineTransform/Reference/reference.html

UIScrollView not functioning correctly after Modal view controller displayed in iOS 5.1

I have a strange problem when using a UIScrollView controller combined with iPhone 4 and iOS 5.1.
I have a UIScrollView which has a content size of 640x480 (double screen effectively) and in addition to the swipe to switch between the two "screens" I also permit the user to tap the screen in response to which I call something like...
[scrollView scrollRectToVisible:(CGRectMake 320,0,320,480) animated:YES];
the first 320 would be 0 if the tap occurred whilst the right hand side of the scroll view was displayed (note the scroll view has paging enabled so it can only come to rest either fully left or fully right).
I also have a situation where I sometimes display an additional view controller modally using presentModalViewController over this view controller containing the scroll view.
Everything works perfectly until the modal view controller is presented and subsequently dismissed after which the scrollRectToVisible method will no longer work if animated is set to YES (if I change animated to NO then it works as expected). Note, the tap is still being registered and the scrollRectToVisible being called, it just doesn't do anything when animated is set to YES).
Here's the kicker, this bug only occurs on an iPhone 4 runnings iOS 5.x.
It works perfectly (even after the modal view controller has been displayed) on my:
iPhone 3G running 4.x,
iPhone 3GS running 3.x,
iPod touch (2nd Gen) running 4.x
and most surprisingly the simulator running 5.x.
I wondered if this was a bug in the animation system so disabled the animation on the modal view controller presentation and dismiss and this had no effect, problem still occurred on the iPhone 4 with iOS 5.1.
Anyone got any ideas as to what might be causing this and how I might work around it?
Finally tracked this down. what a pig...
I'm embedding a view from a view controller as a subview of another view controllers view. So my scroll view contains a view which also has an associated view controller.
Prior to iOS 5.x the methods viewWillAppear, viewWillDisappear, viewDidAppear and viewWillDisappear are never called on the sub views view controllers, only the main view controller. Already knowing this I set up my main view controller to manually call the sub views view controllers methods when these events happen.
However it appears that in iOS 5.x this issue has been "fixed" so where I was manually passing the call to viewWillAppear to my sub view controller I no longer need do this under 5.x as the method automatically gets called under 5.x - as a result it's now being called twice under 5.x but still only once when running on a 4.x or earlier device.
As a result, under 5.x my NSTimer used to call my updateUI method is being created twice, but because in viewDidDisappear I only destroy the timer if it is non nil it only gets destroyed once - therefore I'm leaking NSTimers under 5.x through double allocation where I'm not under 4.x.
As a result of multiple NSTimers hanging around all repeatedly calling my updateUI method is that the constant updating of the UI is killing the animation system and so the animation for the scrollView fails when running on an actual device. I guess it continued working OK on the simulator running 5.x as the CPU in the Mac is more than capable of handling the extra workload and still performing the animations correctly.
A simple check in my viewWillAppear method to ensure the NSTimer hasn't already been created has fixed the problem and has kept compatibility with 4.x and earlier.
I frustratingly run up against these kinds of issues every time Apple update their iOS by major versions... The morale of this story is don't assume that long standing classes still exhibit the same behaviour under different revisions of the OS.
I had the same problem. I realized that after modalViewController is dismissed my UIScrollerView shifts downs by 20px, which is the same height as status bar. So, it means when my UIViewController is loaded and UIScrollView is created, UIScrollView thinks there is no status bar, when actually it is there.
So I tried to put in viewDidLoad:
[[UIApplication sharedApplication] setStatusBarHidden:NO];
Now my UIScrollView always stays under status bar, with Y position 20px. It never shifts down.
I finally managed to get this working on an iPhone4 running 5.1. Ensuring the bounces horizontally property for the scroll view is set fixed the problem, though why having this unchecked should cause the problem in the first place is beyond me - I'm pretty certain this is a bug in iOS.

Disabling buttons before view rotates

So been working on another app recently for iOS which incorporates a UIImagePickerViewController. App is ready to go and all works fine under normal circumstances, but if the user is being eratic and pushing buttons whilst rotating the iPad, then things go slightly awry and views load in the wrong place.
So basically, I want to disable all my buttons before the iPad is rotated and enable them again after the view is done rotating.
I thought this would be easy using the
-(void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
and
-(void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
methods.
But because the UIImagePickerController is being displayed, this for some reason stops these methods from being called. So I can't use these methods.
So basically, what I'm asking is if anybody can think of any other ways that I could achieve this??
Thanks,
Matt
You could subclass UIImagePickerController and then implement those methods on your UIImagePickerController subclass.

Odd behavior when showing UIPopoverController

In my iPad app, I save the state (visible/not visible) of a popover. So, during the launch of the app I initialize the UIPopoverController and tell it to show itself by using presentPopoverFromBarButtonItem:permittedArrowDirections:animated:. For the first argument (UIBarButtonItem), I use self.navigationItem.rightBarButtonItem. However, the popover keeps showing up on the left side of the screen (and not underneath the targeted button).
After the app is launched, the behavior is as expected. Any suggestions how to solve this?
For your information, I initialize the rightBarButtonItem and assign it to the navigationItem in the viewDidLoad method and before asking the popover to present itself. I have tried to call the popover in viewWillAppear and viewDidLoad, but the effect is the same.
My best alternative is to use presentPopoverFromRect:inView:permittedArrowDirections:animated: instead and "guess" the position depending on the orientation of the device.
Update: when I rotate the iPad, the popover does jump to the correct position. It seems that the barButtonItem's position is only determined at the last minute and after I ask my popover to present itself.
In situations like these where timing appears to be important I found that the trick of postponing an action until the next iteration of the run loop helps. If developing for iOS 4.0+, this can be easily achieved with GDC:
// call from viewDidAppear:
dispatch_async(dispatch_get_main_queue(), ^{
// call presentPopoverFromBarButtonItem:permittedArrowDirections:animated: here
});

UIViewControllers not receiving orientation notifications

I've spent the last hour or so trying to work out why not all my UIViewControllers are receiving orientation change notifications.
I've got a subclassed UIViewController attached to the window, that internally creates a few other UIViewControllers to manage smaller portions of the screen which are re-used elsewhere in the application I'm building.
The problem is, only the UIViewController attached to the window is receiving the orientation change notifications.
The other UIViewControllers aren't firing their - (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation duration:(NSTimeInterval)duration methods.
I'm assuming it's expected behaviour, and I can't seem to find anything mentioning it in the docs.
Is there a way to make sure all active UIViewControllers are getting orientation changes? Or does the parent view controller have to tell it's children when changes are occurring?
Cheers.
Are all your view controllers returning YES to shouldAutorotateToInterfaceOrientation: ? If so, I suggest to pass the interface orientation messages from the parent to the children viewControllers, as you suggested.
I have been doing so before and had no problems with that approach so far.