Modifying UINavigationController corrupts navigation stack - ios

I've got a standard UINavigation controller and push my screens with push and pop as normal. However, i have one screen that switches between two view controllers on a button press so the screen flips over top reveal the other viewcontroller and visa versa. You can switch between them at will.
Now, I want the back button to work as normal so I swap the top view controller to achieve this as follows:
-(IBAction)switchToSlowProductEntry:(id)sender
{
NSLog(#"Switching to slow product entry");
// Replace the top view with the findProductView
FindProductView *findProdView = [ProductViewInstances shared].findProductView;
NSMutableArray *views = [self.navigationController.viewControllers mutableCopy];
[views removeLastObject];
[views addObject:findProdView];
// if sender is nil then assume we started from the viewDidLoad so no animation
if(sender)
{
[UIView transitionWithView:self.navigationController.view duration:0.3 options:UIViewAnimationOptionTransitionFlipFromRight animations:^
{
[self.navigationController setViewControllers:views animated:NO];
}
completion:^(BOOL finished) {}];
}
else
[self.navigationController setViewControllers:views animated:NO];
NSLog(#"Views: %#", views);
[views release];
[ProductViewInstances shared].lastScreen = SlowProductEntryView;
}
-(IBAction)switchToQuickProductEntry:(id)sender
{
NSLog(#"Switching to fast product entry");
// Replace the top view with the findProductView
QuickOrderEntryView *quickProductView = [ProductViewInstances shared].quickProductView;
NSMutableArray *views = [self.navigationController.viewControllers mutableCopy];
[views removeLastObject];
[views addObject:quickProductView];
if(sender)
{
[UIView transitionWithView:self.navigationController.view duration:0.3 options:UIViewAnimationOptionTransitionFlipFromLeft animations:^
{
[self.navigationController setViewControllers:views animated:NO];
}
completion:^(BOOL finished) {}];
}
else
[self.navigationController setViewControllers:views animated:NO];
NSLog(#"Views: %#", views);
[views release];
[ProductViewInstances shared].lastScreen = QuickProductEntryView;
}
I have a similar piece of code for the other screen. I'm using the ProductViewInstances class to maintain the two view controllers as I do not want the classes to get unloaded as I'm maintaining stage on the screen.
When you want to move forward from these screens, I do the push as normal to a new screen. It work and I go back after reviewing the products I added. If I press back I get back to the above screen and everything seems normal. However, when I press my custom back button (I need to do processing if back pressed) I run into a problem.
The popViewController does nothing. Here is the code in the base class to manage the custom back button.
-(void) viewDidLoad
{
self.navigationItem.leftBarButtonItem = [[[UIBarButtonItem alloc] initWithTitle:NSLocalizedString(#"Back", nil)
style:UIBarButtonItemStyleBordered
target:self
action:#selector(myCustomBack)] autorelease];
if(![ProductViewInstances shared].findProductView)
{
[ProductViewInstances shared].findProductView = [[FindProductView alloc] init];
[ProductViewInstances shared].findProductView.customer = self.customer;
}
if(![ProductViewInstances shared].quickProductView)
{
[ProductViewInstances shared].quickProductView = [[QuickOrderEntryView alloc] init];
[ProductViewInstances shared].quickProductView.customer = self.customer;
}
}
-(void) goBack
{
if([[ProductViewInstances shared].quickProductView checkIfItemsPending])
{
// Pop up dialog
UIAlertView * alert = [[UIAlertView alloc] initWithTitle:NSLocalizedString(#"Save Entries", nil)
message:NSLocalizedString(#"Your entries will be lost", nil)
delegate:self
cancelButtonTitle:NSLocalizedString(#"Cancel", nil)
otherButtonTitles:NSLocalizedString(#"Save", nil), nil];
[alert show];
[alert release];
}
else
{
// Remove rows from quick item entry screen
[[ProductViewInstances shared].quickProductView removeRowsFromtable];
if(didPressHome)
[self popToSpringBoard:YES];
else
[self.navigationController popViewControllerAnimated:YES];
}
}
So when I press back I have to check if the entries will be lost. The pop to SpringBoard pops back a couple of screens and basically calls the following:
NSArray *controllers = appDelegate.navigationController.viewControllers;
UIViewController *springboard = [controllers objectAtIndex:2];
[appDelegate.navigationController popToViewController:springboard animated:animated];
However, the popViewController animated call does nothing... Like as if it never happened.
Donie

#selector(myCustomBack) will not call goBack unless you left out some code.

Related

Setting NavigationController.Viewcontrollers crashing (with custom transitions)

So this is my viewcontroller hierarchy:
-RootVC
-MapVC
-VC0
-VC1
-VC2
The app starts of by pushing #[Root, MapVC] to the view controller -- All good.
Then, my goal is to have the Map loaded (therefore, I don't want to pop the MapVC) while changing between the four main VCs (MapVC, VC0, VC1, VC2).
To do this, I use the following code:
-(void)presentViewController:(NSString*)viewControllerIdentifier{
UIViewController *vc = [self.storyboard instantiateViewControllerWithIdentifier:viewControllerIdentifier];
if (![[self.navigationController.viewControllers objectAtIndex:[[self.navigationController viewControllers] count]-1] isKindOfClass:[vc class]]){
NSMutableArray *viewControllers = [NSMutableArray arrayWithArray:[[self navigationController] viewControllers]];
if (![[viewControllers lastObject] isKindOfClass:[LLMapViewController class]]) {
[viewControllers removeLastObject];
}
[viewControllers addObject:vc];
[[self navigationController] setViewControllers:viewControllers animated:YES];
}
}
-(void)presentViewController0:(NSNotification*)notif{
[self presentViewController:[notif name]];
}
--
Method to present the map:
-(void)presentMapViewController:(NSNotification*)notif{
if (![[self.navigationController.viewControllers objectAtIndex:[[self.navigationController viewControllers] count]-1] isKindOfClass:[LLMapViewController class]]){
[self.navigationController popViewControllerAnimated:YES];
}
}
Well, it works well if I don't animate this transitions.
Also, when I do the following actions everything works well
App Launches:
->Root
->MapVC
ACTIONS:
0: Select VC0
->Root
->MapVC
->VC0
1: Select VC1 (Pops VC0 and pushes VC1, as you can see in the code above)
->Root
->MapVC
->VC1
2: Select MapVC (Pops VC1)
->Root
->MapVC
The problem is when I try to push another VC having the MapVC as main VC:
3: Select VC0
->Root
->Map
....
CRASH!
It doesn't show any consistent error.
Sometimes it doesn't show any error and sometimes it shows errors like these:
Example 1:
-[NSLayoutConstraint navigationController:animationControllerForOperation:fromViewController:toViewController:]:
Example 2:
-[UILabel navigationController:animationControllerForOperation:fromViewController:toViewController:]:
But it always highlights the part when I am setting the navigationcontroller's viewcontrollers .
MY PROBLEM: I have spent around 8 hours trying to fix this. I have no more ideas on how to debug this.
Can anyone please help me?
P.S. I am using custom transitions to push/pop the controllers.
Here's additional code:
-(id<UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController animationControllerForOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController *)fromVC toViewController:(UIViewController *)toVC {
LLMenuAnimation *animationController = [[LLMenuAnimation alloc] initWithNavigationController:self.navigationController];
switch (operation) {
case UINavigationControllerOperationPush:
animationController.type = AnimationTypePush;
return animationController;
case UINavigationControllerOperationPop:
animationController.type = AnimationTypePop;
return animationController;
default:
NSLog(#"OTHER OPERATION");
return nil;
}
}
--
#pragma mark - Animated Transitioning
-(NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext {
return 0.2;
}
-(void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext {
//Get references to the view hierarchy
UIView *containerView = [transitionContext containerView];
UIViewController *fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
UIViewController *toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
if (self.type == AnimationTypePush) {
//Add 'to' view to the hierarchy with 0.5 scale
toViewController.view.transform = CGAffineTransformMakeScale(0.5, 0.5);
[containerView insertSubview:toViewController.view aboveSubview:fromViewController.view];
//Scale the 'to' view to to its final position
[UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{
// toViewController.view.frame = fromViewController.view.frame;
toViewController.view.transform = CGAffineTransformMakeScale(1.0, 1.0);
} completion:^(BOOL finished) {
[transitionContext completeTransition:YES];
}];
} else if (self.type == AnimationTypePop) {
//Add 'to' view to the hierarchy
[containerView insertSubview:toViewController.view belowSubview:fromViewController.view];
//Scale the 'from' view down
[UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{
fromViewController.view.transform = CGAffineTransformMakeScale(0.5, 0.5);
} completion:^(BOOL finished) {
[transitionContext completeTransition:YES];
}];
}
}
I don't believe that you can use UINavigationController the way you are trying to do. If I have understood what you are trying to do, you are wanting to replace the navigationController's viewControllers property from underneath the navigation controller.
By the way, viewControllers property displayed is a copy. This is the way it is defined in the documentation:
#property(nonatomic, copy) NSArray *viewControllers
Your code:
NSMutableArray *viewControllers = [NSMutableArray arrayWithArray:[[self navigationController] viewControllers]];
if (![[viewControllers lastObject] isKindOfClass:[LLMapViewController class]]) {
[viewControllers removeLastObject];
}
[viewControllers addObject:vc];
[[self navigationController] setViewControllers:viewControllers animated:YES];
}
won't work the way you are expecting. You can push and pop view controllers onto the navigation controller. You can't replace the viewControllers the way you are trying to do.
By the way, the view controller hierarchy you drew in the first few lines of your question above is incomplete. Where is the navigation controller in the hierarchy?

UISplitViewController push multiple detail views iPad upon button click on master view

i have master view controller which consists of several buttons instead of tableview. I want to open a different detail views upon different button clicks.
I have code listed below, but this does not show any changes.
- (IBAction)NewEntryBtn:(UIButton *)sender
{
NSLog(#"new entry btn");
[self.appdelegate.splitViewController viewWillDisappear:YES];
NSMutableArray *viewControllerArray=[[NSMutableArray alloc] initWithArray:[[self.appdelegate.splitViewController.viewControllers objectAtIndex:1]viewControllers]];
[viewControllerArray removeLastObject];
self.secondVC=[[SecondDetailViewController alloc] init];
[viewControllerArray addObject:self.secondVC];
self.appdelegate.splitViewController.delegate = self.secondVC;
[[self.appdelegate.splitViewController.viewControllers objectAtIndex:1] setViewControllers:viewControllerArray animated:NO];
[self.appdelegate.splitViewController viewWillAppear:YES];
}
- (IBAction)EditBtn:(UIButton *)sender
{
[self.appdelegate.splitViewController viewWillDisappear:YES];
NSMutableArray *viewControllerArray=[[NSMutableArray alloc] initWithArray:[[self.appdelegate.splitViewController.viewControllers objectAtIndex:1]viewControllers]];
[viewControllerArray removeLastObject];
self.secondVC=[[SecondDetailViewController alloc] init];
[viewControllerArray addObject:self.secondVC];
self.appdelegate.splitViewController.delegate = self.secondVC;
[[self.appdelegate.splitViewController.viewControllers objectAtIndex:1] setViewControllers:viewControllerArray animated:NO];
[self.appdelegate.splitViewController viewWillAppear:YES];
}
could anyone suggest changes?
Well, you can do this by only one method. First set tag to all the buttons and add reference of all the buttons to single method.
- (IBAction)btnClicked:(id)sender
{
int btnNo = ((UIControl *) sender).tag;
NSLog(#"Button Clicked - %d", btnNo);
if (btnNo == 1)
{
// Navigate to first detail view controller
}
else if (btnNo == 2)
{
// Navigate to second detail view controller
}
.
.
and so on.
}

When to call addChildViewController

I'm trying to have something similar to a UINavigationController so I can customize the animations. To start, I'm just using Apple stock animations. Here's my containerViewController:
- (void)loadView {
// Set up content view
CGRect frame = [[UIScreen mainScreen] bounds];
_containerView = [[UIView alloc] initWithFrame:frame];
_containerView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
self.view = _containerView;
}
- (id)initWithInitialViewController:(UIViewController *)vc {
self = [super init];
if (self) {
_currentViewController = vc;
[self addChildViewController:_currentViewController];
[self.view addSubview:_currentViewController.view];
[self didMoveToParentViewController:self];
_subViewControllers = [[NSMutableArray alloc] initWithObjects:_currentViewController, nil];
}
return self;
}
- (void)pushChildViewController:(UIViewController *)vc animation:(UIViewAnimationOptions)animation {
vc.view.frame = _containerView.frame;
[self addChildViewController:vc];
[self transitionFromViewController:_currentViewController toViewController:vc duration:0.3 options:animation animations:^{
}completion:^(BOOL finished) {
[self.view addSubview:vc.view];
[vc didMoveToParentViewController:self];
[self.subViewControllers addObject:vc];
}];
}
- (void)popChildViewController:(UIViewController *)vc WithAnimation:(UIViewAnimationOptions)animation {
// Check that there is a view controller to pop to
if ([self.subViewControllers count] <= 0) {
return;
}
NSInteger idx = [self.subViewControllers count] - 1;
UIViewController *toViewController = [_subViewControllers objectAtIndex:idx];
[vc willMoveToParentViewController:nil];
[self transitionFromViewController:vc toViewController:toViewController duration:0.3 options:animation animations:^{
}completion:^(BOOL finished) {
[vc.view removeFromSuperview];
[vc removeFromParentViewController];
[self didMoveToParentViewController:toViewController];
[self.subViewControllers removeObjectAtIndex:idx];
}];
}
I have this ContainerViewcontroller as my rootViewController of the window. I can add my initial viewController and push a view controller. When I try to pop though, I get
ContainerViewController[65240:c07] Unbalanced calls to begin/end appearance transitions for <SecondViewController: 0x8072130>.
I'm wondering what I am doing wrong. I figured my initialViewController is still underneath the secondViewController. Any thoughts? Thanks!
I don't know if this is what's causing your problem, but shouldn't this:
[self didMoveToParentViewController:toViewController];
be:
[toViewController didMoveToParentViewController:self];
Also, I'm not sure what you're doing with the subViewControllers array. It seems to be a duplication of the childViewControllers array that is already a property of a UIViewController.
One other thing I'm not sure is right. In your pop method your toViewController is the last controller in the _subViewControllers array. Don't you want it to be the second to last? Shouldn't the last be the one you're popping? You're popping vc, which is a controller you're passing in to the method, I don't understand that.
This is the way I've made a navigation like controller. In its containment behavior, it acts like a navigation controller, but without a navigation bar, and allows for different transition animations:
#implementation ViewController
-(id)initWithRootViewController:(UIViewController *) rootVC {
if (self = [super init]) {
[self addChildViewController:rootVC];
rootVC.view.frame = self.view.bounds;
[self.view addSubview:rootVC.view];
}
return self;
}
-(void)pushViewController:(UIViewController *) vc animation:(UIViewAnimationOptions)animation {
vc.view.frame = self.view.bounds;
[self addChildViewController:vc];
[self transitionFromViewController:self.childViewControllers[self.childViewControllers.count -2] toViewController:vc duration:1 options:animation animations:nil
completion:^(BOOL finished) {
[vc didMoveToParentViewController:self];
NSLog(#"%#",self.childViewControllers);
}];
}
-(void)popViewControllerAnimation:(UIViewAnimationOptions)animation {
[self transitionFromViewController:self.childViewControllers.lastObject toViewController:self.childViewControllers[self.childViewControllers.count -2] duration:1 options:animation animations:nil
completion:^(BOOL finished) {
[self.childViewControllers.lastObject removeFromParentViewController];
NSLog(#"%#",self.childViewControllers);
}];
}
-(void)popToRootControllerAnimation:(UIViewAnimationOptions)animation {
[self transitionFromViewController:self.childViewControllers.lastObject toViewController:self.childViewControllers[0] duration:1 options:animation animations:nil
completion:^(BOOL finished) {
for (int i = self.childViewControllers.count -1; i>0; i--) {
[self.childViewControllers[i] removeFromParentViewController];
}
NSLog(#"%#",self.childViewControllers);
}];
}
After Edit: I was able to duplicate the back button function with this controller by adding a navigation bar to all my controllers in IB (including in the one that is the custom container controller). I added a bar button to any controllers that will be pushed, and set their titles to nil (I got some glitches if I left the title as "item"). Deleting that title makes the button disappear (in IB) but you can still make connections to it in the scene list. I added an IBOutlet to it, and added this code to get the function I wanted:
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
if (self.isMovingToParentViewController) {
self.backButton.title = [self.parentViewController.childViewControllers[self.parentViewController.childViewControllers.count -2] navigationItem].title;
}else{
self.backButton.title = [self.parentViewController.childViewControllers[self.parentViewController.childViewControllers.count -3] title];
}
}
I've shown two different ways that worked to access a title -- in IB you can set a title for the controller which I used in the else clause, or you can use the navigationItem title as I did in the if part of the clause. The "-3" in the else clause is necessary because at the time viewWillAppear is called, the controller that is being popped is still in the childViewControllers array.
addChildViewController should be called first
For adding / removing, you can refer to this great category and have no worry when to call it:
UIViewController + Container
- (void)containerAddChildViewController:(UIViewController *)childViewController {
[self addChildViewController:childViewController];
[self.view addSubview:childViewController.view];
[childViewController didMoveToParentViewController:self];
}
- (void)containerRemoveChildViewController:(UIViewController *)childViewController {
[childViewController willMoveToParentViewController:nil];
[childViewController.view removeFromSuperview];
[childViewController removeFromParentViewController];
}
In addition to rdelmar's answer you should not be calling addView/removeFromSuperview transitionFromViewController does this for you, from the documentation:
This method adds the second view controller’s view to the view
hierarchy and then performs the animations defined in your animations
block. After the animation completes, it removes the first view
controller’s view from the view hierarchy.

Views Not Resizing After Rotation In Custom Container Controller

I've made a test app to familiarize myself with making a custom container view controller. If I rotate the device when the app first starts or after switching to a different view controller, the new view resizes to take up the whole screen, as I intended. However, if I rotate after the app starts, and then switch to a new view controller, the view keeps its portrait size instead of getting shorter and wider (actually it's slightly different -- it goes from 320,460 to 300,480). The master view controller is alloc init'd in the app delegate (no xib) and set as the window's root view controller. Here is the code I have in my MasterViewController (the custom container controller):
- (void)viewDidLoad {
[super viewDidLoad];
WelcomeController *welcome = [[WelcomeController alloc] initWithNibName:#"ViewController" bundle:nil];
self.currentController = welcome;
[self addChildViewController:welcome];
[self.view addSubview:welcome.view];
UISwipeGestureRecognizer *swipeLeft = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(swipeLeft:)];
swipeLeft.direction = UISwipeGestureRecognizerDirectionLeft;
[self.view addGestureRecognizer:swipeLeft];
}
- (void)swipeLeft:(UISwipeGestureRecognizer *)gesture {
if (gesture.state == UIGestureRecognizerStateRecognized) {
UIActionSheet *sheet =[[UIActionSheet alloc] initWithTitle:#"Select A Destination" delegate:self cancelButtonTitle:#"Cancel" destructiveButtonTitle:nil otherButtonTitles:#"welcome",#"Play",#"Scores", nil];
[sheet showInView:self.view];
}
}
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
switch (buttonIndex) {
case 0:{
if ([self.currentController class] != [WelcomeController class] ) {
WelcomeController *welcome = [[WelcomeController alloc] initWithNibName:#"ViewController" bundle:nil];
[self addChildViewController:welcome];
[self moveToNewController:welcome];
}
break;
}
case 1:{
if ([self.currentController class] != [PlayViewController class] ) {
PlayViewController *player = [[PlayViewController alloc] initWithNibName:#"PlayViewController" bundle:nil];
[self addChildViewController:player];
[self moveToNewController:player];
}
break;
}
case 2:{
if ([self.currentController class] != [HighScores class] ) {
HighScores *scorer = [[HighScores alloc] initWithNibName:#"HighScores" bundle:nil];
[self addChildViewController:scorer];
[self moveToNewController:scorer];
}
break;
}
case 3:
NSLog(#"Cancelled");
break;
default:
break;
}
}
-(void)moveToNewController:(id) newController {
[self.currentController willMoveToParentViewController:nil];
[self transitionFromViewController:self.currentController toViewController:newController duration:.6 options:UIViewAnimationOptionTransitionCrossDissolve animations:^{}
completion:^(BOOL finished) {
[self.currentController removeFromParentViewController];
[newController didMoveToParentViewController:self];
self.currentController = newController;
}];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return YES;//(interfaceOrientation == (UIInterfaceOrientationPortrait | UIInterfaceOrientationLandscapeLeft));
}
Any ideas why this is happening (I don't know if this means that the master view controller's view isn't resizing, but when I get this non-resizing behavior the gesture recognizer only responds in the narrow view, not over the whole screen)?
You are not sending rotation messages to your child view controllers. At least not in the code you posted. After switching Child Controller you are even removing previous child from ChildViewControllers array with [self.currentController removeFromParentViewController] so even if you implement - (BOOL)automaticallyForwardAppearanceAndRotationMethodsToChildViewControllers you have always only one ChildViewController in your ParentViewController.
I have got this working, so i will paste you how am i doing this. First i create all my ViewControllers, add them as child view controllers to ParentViewController. Then call didMoveToParentViewController: method.
//Controller1
Controller1 *c1 = [[Controller1 alloc] init];
c1.view.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
[self addChildViewController:c1];
[c1 didMoveToParentViewController:self];
//Controller2
Controller2 *c2 = [storyboard instantiateViewControllerWithIdentifier:#"c2"];
index.view.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
[self addChildViewController:c2];
[c2 didMoveToParentViewController:self];
c2.view.frame = m_contentView.frame;
[self.view addSubview:c2.view]; //It is in initial screen so set it right away
m_selectedViewController = c2;
//Controller3
Controller3 *c3 = [storyboard instantiateViewControllerWithIdentifier:#"c3"];
compare.view.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
[self addChildViewController:c3];
[c3 didMoveToParentViewController:self];
m_controllers = [NSArray arrayWithObjects:c1, c2, c3, nil]; //Hmm now i think this is not needed, I can access viewController directly from self.childViewControllers array
Then I implemented
- (BOOL)automaticallyForwardAppearanceAndRotationMethodsToChildViewControllers
{
return YES;
}
Switching to child view controller is done with this code
if (value < m_controllers.count)
{
UIViewController *contentViewController = [m_controllers objectAtIndex:value];
contentViewController.view.frame = m_contentView.frame;
[self transitionFromViewController:m_selectedViewController toViewController:contentViewController duration:0 options:UIViewAnimationOptionTransitionNone animations:nil completion:^(BOOL finished) {
m_selectedViewController = contentViewController;
}
];
}
This should be enough. But i have got some issues with this so i send rotation messages to unactive Childs myself.
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
for (UIViewController *vc in m_controllers)
{
if(vc != m_selectedViewController)
[vc willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration];
}
}
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
for (UIViewController *vc in m_controllers)
{
if(vc != m_selectedViewController)
[vc willAnimateRotationToInterfaceOrientation:toInterfaceOrientation duration:duration];
}
}
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
{
for (UIViewController *vc in m_controllers)
{
if(vc != m_selectedViewController)
[vc didRotateFromInterfaceOrientation:fromInterfaceOrientation];
}
}
manually added
self.view.autoresizesSubviews = YES;
inside
- (void)viewDidLoad
and it solved the problem,
for some reason the value inside storyboard was not being used i guess

Trouble with controlling a ScrollView from a Popover

I'm a junior and I have been really struggling to get this to work, would really appreciate some help.
I am trying to build an App where you can scroll through different WebViews by selecting an item from a table in a popover (while the popover remains in place). Unfortunately, I can't get my scrollView to move when I select an item from the popover view.
I have set up a UIScrollView with page control in a main UIViewController. The scrollView is populated with (pageViewController) UIWebViews. The main UIViewController has a nav bar with a button, when the button is clicked it creates a Popover View. When I select an item from the table in the popover view I want my UIScrollView to scroll to a certain position (equates to a selected page), but the scrollView does not move.
The method below takes the value selected from the popover and uses the page number to determine where the scrollView should scroll to, but it doesn't work because at this point my scrollView is Null.
I can supply more code if needed.
main UIViewController.m code:
- (void)setDetailItem:(id)newDetailItem {
if (detailItem != newDetailItem) {
[detailItem release];
detailItem = [newDetailItem retain];
NSString *pgnum = [[NSString alloc] initWithString:[detailItem description]];
int pg;
if(pgnum == #"Page 1"){
pg =1;
}
if(pgnum == #"Page 2"){
pg =2;
}
if(pgnum == #"Page 3"){
pg =3;
}
[pgnum release];
pageControl.currentPage = pg;
[self loadScrollViewWithPage:pg - 1];
[self loadScrollViewWithPage:pg];
[self loadScrollViewWithPage:pg + 1];
CGRect frame = scrollView.frame;
frame.origin.x = frame.size.width * pg;
frame.origin.y = 0;
[scrollView scrollRectToVisible:frame animated:YES];
pageControlUsed = YES;
}
if (popoverController != nil) {
[popoverController dismissPopoverAnimated:YES];
}
}
This is how I triggered the popOverController
The infoButton is on the navbar.
The scrollView is NOT NULL in the infoButton
- (void)infoButton:(id)sender {
NSLog(#"Entering: infoButton");
// [self inspectView:self.view level:#""];
if (self.popoverController == nil) {
PopoverViewController *popoverViewController =
[[PopoverViewController alloc]
initWithNibName:#"PopoverViewController"
bundle:[NSBundle mainBundle]];
popoverViewController.navigationItem.title = #"Navigation";
UINavigationController *navController =
[[UINavigationController alloc]
initWithRootViewController:popoverViewController];
UIPopoverController *popover =
[[UIPopoverController alloc]
initWithContentViewController:navController];
popover.delegate = self;
[popoverViewController release];
[navController release];
self.popoverController = popover;
[popover release];
//NSLog(#"User pressed the info button");
}
[self.popoverController presentPopoverFromBarButtonItem:sender permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES]; }
UIPopover, being neither the most obvious class to use memory-management wise, nor the most stable, does not require you to release it before you present it. In fact, doing so causes it to throw a fatal exception! Popovers should be released after they are removed from the screen, and/or in -dealloc.

Resources