UIWindow rotation bug in iOS8 for custom alert - ios

I've updated my custom alert class (which is a UIWindow subclass) in iOS8 to set its rootViewController to the UIViewController it is being presented on. This enables the app to automatically rotate my custom alert instead of having to do it manually.
It works well but I'm finding one situation where it doesn't rotate: when I'm on the UIViewController that appears when the app is first launched (which also happens to be the rootViewController of my app delegates window property).
Is this because UIViewController can't be the rootViewController of two UIWindows or is it a bug? Does anyone have a work around for this? It works perfectly on every other UIViewController that I display an alert.

Related

iOS8 - prevent rotation on presenting viewController

We have a MainViewController with a tableView, and it presents a new modalViewController.
The MainViewController is restricted to portrait only, and the modalViewController can rotate.
The problem is in iOS8, that when the modalViewController rotates, the callback method of rotation in iOS8 in MainViewcontroller is called - - (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator
Thus, the UITableView is getting its data reloaded, which is a behaviour we don't want.
Can we prevent this feature of iOS 8, and not rotate the presenting UIViewController?
So after long days of searching and investigating, I finally came up with a possible solution.
First of all, I can use navigation controller and push the viewController instead of presenting it, but it breaks my code and just isn't so true.
The second thing I can do is not setting constraints. I still can use autolayout, but if I don't set constraints, and let the default constraints to be set, the tableView doesn't get reloaded. of course this is also isn't very smart thing to do, as I have many elements in my viewController.
Finally, I figured out that I can show this "modal" viewController in another UIWindow. I create UIWindow and set the modalViewController as its rootViewController.
I put some example project in git:
https://github.com/OrenRosen/ModalInWindow
Hope it will be helpful.
I did something similar with a navigation controller, that wouldn't rotate unless the top pushed controller does rotate.
In your case check if the main controller is presenting another controller. If it isn't then just reject rotation, otherwise return whatever the presented controller returns for the rotation method.
As for your table view, it shouldn't get reloaded because of rotations.
In iOS 8 the view that rotates when you change the device orientation is the first view added to the UIWindow. So, if you save a reference to it in your presentedController, you can overwrite the shouldAutorotate and supportedInterfaceOrientations values.

Detect popover dismiss in iOS8

in my iPad-app I connected a UIButton to another UIViewcontroller by just dragging in Storyboard and chose popover as segue. Everything is working fine, but the user can dismiss the popover by touching just somewhere besides the popover right.
How can I detect that the popover has dismissed in iOS8? In iOS7 I could just use the UIPopoverDelegate -popoverDidDidmiss...
But this is not working anymore!? I googled a lot but could not find any solution.
You put your
-(void)popoverControllerDidDismissPopover:(UIPopoverController *)popoverController
in the UIViewController where the start UIButton is ? (not in another popover UIViewcontroller ?)
That work well for me with iOS 8.1...
You have to delegate to the initial UIViewController for that.
I assume you set the delegate properly, but do you retain the popover, i.e. assign it to a strong property? In ios7 if you didn't retain the popover you would get exception: '[UIPopoverController dealloc] reached while popover is still visible.' In ios8 this is not longer the case, so you get the working popover and you can dismiss it, but the delegate methods are not called anymore.
(Frankly speaking, I'm not sure why this is so. I'd suppose that at least "should dismiss popover" should be called anyway).
You should probably use UIPopoverControllerDelegate and the method
popoverControllerDidDismissPopover:
to accomplish what you need.
in iOS8, it is using the UIViewController's UIPopoverPresentationController to present the popover. (Optionally you still can use back the old UIPopoverController to build the popover manually.
If you are using storyboard on iOS8, you can set the UIViewController's popoverPresentationController delegate to handle the followings:
popoverPresentationControllerShouldDismissPopover:
popoverPresentationControllerDidDismissPopover:

ViewDidLoad does not get called

I'm developing an app for iPhone and iPad. The app has a TabBar to switch between ViewControllers. I know that when the app is developed for both devices all I have to do is create the Storyboard items again for iPad and just connect the properties with the ViewControllers that I already have i.e FirstViewController is the same for the iPhone and iPad app.
In the iPhone app there are three tabs but because iPad's screen size is bigger I would like to have two tabs for the iPad version. So I would like to merge SecondViewController and ThirdViewController for the iPad app. So I decided to subclass UIViewControllerand called it MyViewController. Inside MyViewController goes the code of SecondViewController and ThridViewController.
In the simulator I can see the background image and the Storyboard items of the MyViewController's view. The problem is that viewDidLoad method doesn't get called on MyViewController class (I have a NSLog statement right after [super viewDidLoad]). I checked that in my storyboard in Idendity Inspector the class is MyViewController. Also tried to create a completely new ViewController with a new subclass but also for that new ViewController the method viewDidLoad method is not getting called.
Tab bar controllers do not release controller-A when you move to controller-B and vice versa.They are allocated once and hence you don't see viewDidLoad when the tabs are shuffled.
You might have to check viewWillAppear method to see it the viewControllers are called or not!
You could use these life cycle events:
Responding to View Events
– viewWillAppear:
– viewDidAppear:
– viewWillDisappear:
– viewDidDisappear:
– viewWillLayoutSubviews
– viewDidLayoutSubviews
- (void)viewDidAppear:(BOOL)animated
viewDidAppear will be called when your view visible again

UITabBarController and rotation iOS6

Happy Memorial Day for those in America!
I am new to iOS and Objective-C programming; a few weeks ago I inherited an iPad app-in-development that was being designed for iOS 5. I now have everything working except the rotation in iOS 6. I know that iPad apps should rotate to every orientation be default (which is what I want), yet mine does not. Everything rotates perfectly in iOS 5, and I can get my splash screen to rotate perfectly in iOS 6, but that is all. I cannot get the activities (once you click through the splash screen) to rotate properly.
I have searched stackoverflow and other websites to figure out what I must do, so I know to implement -(BOOL)shouldAutorotate and -(NSUInteger)supportedInterfaceOrientations in any specific ViewController to control that view's orientation behavior. I've read that having that different rotation behavior in one VC can affect the entire app. So I made sure that every VC that I could find** would now implement those two iOS 6 methods to return YES and UIInterfaceOrientationMaskAll, respectively. That didn't work. I read about returning self.tabBarController.shouldAutorotate and self.tabBarController.supportedInterfaceOrientations in those methods to ensure that the tabbar rotation behavior is consistent, but that didn't work. I have read about implementing a category (UITabBarController+autoRotate.m and .h) that implements these two methods, and that didn't work. I have read about subclassing the tabBarController, and I think my code does that: in my appDelegate, I call
[myWindow setRootViewController:activityViewController],
where activityViewController is an instance of class BicycleFamilyAcitivityViewController, which is from
#interface BicycleFamilyActivityViewController : UIViewController <UITabBarControllerDelegate>
When I investigate what is being called during the successful splash screen rotation using the iOS 6 simulator, I notice that those two implemented methods in BicycleFamilyAcitivityViewController are being called (twice each, actually) and that -(void)willAnimateRotationToInterfaceOrientation:duration is as well. When I try to rotate while viewing an activity (after clicking through the splash screen), those two methods are only called once, and -(void)willAnimateRotationToInterfaceOrientation:duration is not called. In both instances, the appDelegate's -(NSUInteger)application:supportedInterfaceOrientationsForWindow method is called.
Any advice on how to get rotation to work throughout the entire app? Even if it's just pointing to an answer on StackOverflow that I haven't yet seen (or fully understood), I would be most grateful.
Many thanks in advance!
Bernie
** In looking for VC classes in the project, I made sure to consider any class that implemented the rotation method of iOS 5: -(BOOL)shouldAutorotateToInterfaceOrientation:interfaceOrientation
In iOS 6 the Orientation functions have changed. Your set up should look like this in your viewControllers:
-(NSUInteger)supportedInterfaceOrientations {
return UIInterfaceOrientationMaskAll;
}
-(UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
return UIInterfaceOrientationLandscapeRight;
}
-(BOOL)shouldAutorotate {
return TRUE;
}
UIInterfaceOrientationMaskAll is all orientations, more information here.
Someone in-house figured out the problem. I thought I would post the answer to help anyone who has a similar predicament.
What I had tried (among other things) was: setting the UIWindow in my appDelegate class to be my instance of a subclass (BicycleFamilyAcitivityViewController) of UIViewController. In my appDelegate, I had:
[myWindow setRootViewController:activityViewController];
where activityViewController is an instance of a subclass of UIViewController.
But I should have created an additional UIWindow via delegate, then assign the TabBarController (tbc) as it's root VC when I build my TabBarController. In my primary view controller class, I had a buildTabBarController function. So these two lines in that function allowed my rotation to work:
UIWindow *keyWindow = [[[UIApplication sharedApplication] delegate] window];
[keyWindow setRootViewController:tbc];
Hope this helps!

willHideViewController called despite the app is in landscape mode

I'm developing an iPad app that launches in landscape mode.
The first screen displays a UISplitViewController and my issue is that altough the app is in landscape mode the delegate is notified on splitViewController:willHideViewController:withBarButtonItem:forPopoverController: despite that the documentation states that:
When the split view controller rotates
from a landscape to portrait
orientation, it normally hides one of
its view controllers. When that
happens, it calls this method to
coordinate the addition of a button to
the toolbar (or navigation bar) of the
remaining custom view controller. If
you want the soon-to-be hidden view
controller to be displayed in a
popover, you must implement this
method and use it to add the specified
button to your interface.
As the app is in landscape mode and not transitioning to portrait I don't get why my delegate is notified. Why is it so?
valentin, to directly answer "why is it so?", i think the answer is simply that it's a bug in the implementation of their API.
as you seem to have found, when in landscape orientation, it calls the above when it sort of seems that it shouldn't, and then calls splitViewController:willShowViewController:invalidatingBarButtonItem: .
also, i discovered that when in portrait orientation, it sends a very early message (i.e. before the view.frame has been adjusted) to splitViewController:willHideViewController:withBarButtonItem:forPopoverController: .
the one thing i saw that annoyed me the most was that, using the code provided from their template creation, the button bar would appear and then disappear at startup.
my solution was to implement a workaround, which i have posted on git#github.com:johnkdoe/freeforall.git in the class KludgeWorkaroundForBuggySplitViewDelegateStartup .
make this a superclass of your current detail view controller class, as in
//#interface MyViewController : UIViewController<UISplitViewControllerDelegate>
#interface MyViewController : KludgeWorkaroundForBuggySplitViewDelegateStartup
this will set the initial button bar title to Master if you don't have something you prefer. you can override this by overriding the #property getter in your subclass implementation. if you want to do more than what's in this kludgeWorkaround class, you can override these yourself and (either copy and paste or) call [super ...] on them prior to doing your own work.
i can't say this solves the problem of what appears to me to be an implementation bug, but the workaround gets rid of the brief appearance of the button bar at startup of a split-view-controller app in landscape mode.

Resources