• Open Menu Close Menu
  • Apple
  • Shopping Bag
  • Apple
  • Mac
  • iPad
  • iPhone
  • Watch
  • TV
  • Music
  • Support
  • Search apple.com
  • Shopping Bag

Lists

Open Menu Close Menu
  • Terms and Conditions
  • Lists hosted on this site
  • Email the Postmaster
  • Tips for posting to public mailing lists
Re: [iPhone] Strange behavior with modal view controllers
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [iPhone] Strange behavior with modal view controllers


  • Subject: Re: [iPhone] Strange behavior with modal view controllers
  • From: Michael Babin <email@hidden>
  • Date: Wed, 17 Jun 2009 09:25:44 -0500

On Jun 17, 2009, at 5:43 AM, WT wrote:

Is there any known reason whatsoever why presentModalViewController would do absolutely nothing?

Possibly, depending on the meaning of "known". In any case, let's investigate further using the sample project you put together (referenced in a follow-up message).


In an iPhone game app I'm working on, I have a tab-bar with 5 items, 2 of which are managed by the SettingsViewController and the GameViewController, respectively. The player can freely switch between any two views by tapping the appropriate button on the tab- bar, *except* that - once the game view has been switched into - the player can only switch between the game view and the settings view. This allows the player to change settings within the app, but without being in a game, as well as while playing a game, and prevents the player from accessing other views that are not supposed to be accessible during game play.

In order to implement this, I use the tab-bar delegate method - tabBarController: shouldSelectViewController: to detect when the player is attempting to switch to the game view, make the game view controller the active one (directly, not through the tab-bar controller), release the tab-bar controller, and then return NO:

I'm not 100% certain, but I believe this delegate method is new in iPhone OS 3.0 (couldn't find it in the 2.2.1 docs). The project you put together also specifies the iPhone 3.0 SDK. I don't believe it is kosher to speak of these things on the list at this point, but we can easily switch to using the iPhone OS 2.2.1 SDK and substitute the - tabBarController:didSelectViewController: delegate method in their place.


- (BOOL) tabBarController: (UITabBarController*) tab_bar_controller
shouldSelectViewController: (UIViewController*) view_controller
{
BaseViewController* curVC = (BaseViewController*) tabBarController.selectedViewController;
BaseViewController* newVC = (BaseViewController*) view_controller;


   NSUInteger kindOfCurVC = curVC.viewControllerKind;
   NSUInteger kindOfNewVC = newVC.viewControllerKind;

   if (kindOfNewVC == kindOfCurVC)
   {
       // Since the tab-bar view responds to taps on an already
       // selected tab-bar item, and we don't want to do work that
       // has already been done, we should return NO in this case.

       return NO;
   }
   else
   if (kindOfNewVC == kViewControllerKindGame)
   {
       // Switching to the game view. Return NO because
       // the active view controller will change directly
       // to the game view controller and the tab-bar controller
       // will never get a chance to switch to the game view.

       [tabBarController.view removeFromSuperview];
       [window addSubview: gameViewController.view];

       [tabBarController release];
        tabBarController = nil;

       return NO;
   }
   else
   {
       // Switching to a view other than the game view.

       return YES;
   }
}

At this point, it's as if I never had a tab-bar controller. Of course, I need to have retained both the SettingsViewController and the GameViewController, which I did when I grabbed them from the tab- bar view controllers array back in the - applicationDidFinishLaunching: method.

So, now, when I want to switch between the game and settings views, I use a modal view controller scheme, with the SettingsViewController being the modal partner of the GameViewController. I also have a button on the settings view, that is hidden when the settings view controller is being managed by the tab-bar but visible when not. The button's action triggers the dismissal of the modal behavior, returning to the game view.

Everything works great, except for one thing: the call

[gameViewController presentModalViewController: settingsViewController animated: YES];

does absolutely nothing! Moreover, I've verified that, after that call, gameViewController.modalViewController is nil. The AppDelegate method

- (void) switchFromGameToSettings
{
   NSLog(@"AppDelegate: -switchFromGameToSettings");

[gameViewController presentModalViewController: settingsViewController animated: YES];

NSLog(@"settingsViewController = %@", settingsViewController);
NSLog(@"gameViewController = %@", gameViewController);
NSLog(@"gameViewController.modalViewController = %@", gameViewController.modalViewController);


   // Tell the settings view controller that it is now in-game.
   settingsViewController.inGame = YES;
}

(triggered by a tap on the appropriate button on the game view, which triggers an action method in the game view controller, which calls -switchFromGameToSettings on the application delegate)

results in:

AppDelegate: -switchFromGameToSettings
settingsViewController = <SettingsViewController: 0xd1b720>
gameViewController = <GameViewController: 0xd1bd40>
gameViewController.modalViewController = (null)

My first thought was that perhaps either one or both of the view controllers might still be tied up with the tab-bar controller, somehow, even though I've killed the tab-bar by this point.

I think your first thought is probably correct.

So, I tried a little hack where I create a fresh new pair of view controllers just prior to the presentModalViewController call, and now things do work correctly.

A little more investigation then revealed that I don't need to have a fresh new SettingsViewController object, ie, the one I grabbed from the tab-bar works just fine. The problem is then with the GameViewController object.

I suspect that the problem is that your view controllers (Game and Settings) are left in a "confused" state, with their parent view controller still referring to the removed and released UITabBarController. Since the parentViewController and tabBarController properties of the UIViewController are read-only, you can attack this from the other end by removing them from the UITabBarController's list of viewControllers before releasing it. Like so:


- (void)tabBarController:(UITabBarController *)tab_bar_controller
didSelectViewController:(UIViewController *)newVC
{
if (newVC == gameViewController)
{
[tabBarController.view removeFromSuperview];
[window addSubview: gameViewController.view];

NSMutableArray *tabViewCtlrs = [[tabBarController viewControllers] mutableCopy];
[tabViewCtlrs removeObject:gameViewController];
[tabViewCtlrs removeObject:settingsViewController];
[tabBarController setViewControllers:tabViewCtlrs];
[tabViewCtlrs release];
tabViewCtlrs = nil;


        [tabBarController release];
         tabBarController = nil;
    }
}

In my modified copy of your sample project, this change seems to do the trick.

_______________________________________________

Cocoa-dev mailing list (email@hidden)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden


  • Follow-Ups:
    • Re: [iPhone] (SOLVED) Strange behavior with modal view controllers
      • From: WT <email@hidden>
References: 
 >[iPhone] Strange behavior with modal view controllers (From: WT <email@hidden>)

  • Prev by Date: Re: Group CGAffineTransform Animations?
  • Next by Date: repeatable random numbers in an object
  • Previous by thread: [iPhone] Strange behavior with modal view controllers
  • Next by thread: Re: [iPhone] (SOLVED) Strange behavior with modal view controllers
  • Index(es):
    • Date
    • Thread