Friday, August 26, 2011

Changing the root controller



As discussed in my last post, I'm trying to zero in on how to change the root controller for my current app. From Google, I see that dynamically changing the root (setRootController) isn't supported. However, this post in SO gives some interesting information:

http://stackoverflow.com/questions/1663003/rootviewcontroller

I'm learning this right now so the questions might be a little juvenile. Here's what I'm trying to do. I have the first view come up with a cell of the table populated statically, when you select one of the cells it will pull up a form to input data.

Now, I've been reading the documentation about navigation buttons and navigation in general and it seems that I need two separate viewControllers. One for the basic app and another for the new page being brought forward when the cell is picked. Is this correct?

Sorry, this might be a little bit basic but I'm not sure what to do here. Thanks.



This sounds like what I did - I have a table that switches to the detail view when an item is clicked. I must already be doing this.

Here's the selected answer to the SO question cited above:

Basically you need to create a second UIViewController subclass, this viewcontroller needs to be attached to your main window when switching views.

-(IBAction) SwitchView:(id)sender
{
MySubViewController *subViewController = [[MySubViewController] alloc]
initWithNibName:@"SubView" bundle:nil];
self.view insertSubView:subViewController.view atIndex:0];
[subViewController release];
}


Well, this looks kind of familiar.

Let's see what's in "QuestionController", the rootController of our app:

#pragma mark UITableViewDelegate
- (void)tableView:(UITableView *)tv
didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{

QuizAppDelegate *delegate =
(QuizAppDelegate *)[[UIApplication sharedApplication] delegate];

AnswersController *answersController =
[[ AnswersController alloc] initWithIndexPath:indexPath];

[ delegate.navController pushViewController:answersController animated:YES];
[ answersController release];

[tv deselectRowAtIndexPath:indexPath animated:YES];
}


Right. So, it's actually invoking the app delegate, using [UIApplication sharedApplication], then getting the delegate, and casting it to QuizAppDelegate. Then it's allocating the AnswersController - no problem there.

Then, it's grabbing the app delegate's nav controller, and pushing the answer controller onto it. This must actually then transfer control to the answer controller.

It's becoming clear that my optimal course of action will be to create that new, very simple, single button view, and have the button allocate to the question controller. But we knew that. The question is, how to untangle the root controller from the main controller, i.e. the app delegate?

Here's the problem:



@class RootController;
@class Question;
@class AppState;

@interface QuizAppDelegate : NSObject {
UIWindow *window;
RootController *viewController;
UINavigationController *navController;
Question *currentQuestion;
AppState *appState;

}

@property (nonatomic, retain) IBOutlet UIWindow *window;
@property (nonatomic, retain) IBOutlet RootController *viewController;
@property (nonatomic, retain) IBOutlet UINavigationController *navController;
@property (nonatomic, retain) Question *currentQuestion;
@property (nonatomic, retain) AppState *appState;


@end


The above is the header for the the app delegate. And it's hooked up to root controller *and* the UINavigationController via IBOutlets.

We need to change the RootController for a new rootController - our new, one-button view. I know there was a way to specify that in the xlb, but I didn't have any luck the last time I tried it. Let's add the one-button view first. Where to start?

Ok, I just refactored "viewController" to "rootViewController" to make it less confusing - at least temporarily. I'm switching it out for a different one later.

Xcode offers to save a snapshot before and after for the refactor. Man, this is so sweet. It's like coming in from the cold.

Another very cool enhancement with XCode 4 - if you edit the implementation file, it automatically brings up the header file, side by side - so nice.



Ok. Now, I want to rename the RootController to QuestionController. The trick with that is not to do it from the project navigator, but rather from the code window, and it works and tests out perfectly. And now I can rename the recently renamed rootViewController to QuestionViewController.

Great. Now let's look at the xlb for the app delegate - MainWindow.xlb.

Ok, when we right-click on AppDelegate object to look at its outlets, it looks like instead of renaming rootViewController, it actually went ahead and *added* the questionViewController. This may be good news indeed. It probably means if we declare our new "StartController" as an IBOutlet, it will become available to the app delegate to delegate to. Great!

So, now we're getting to the point of just creating the StartControllerView and hooking it up to the QuizAppDelegate through the interface builder. Let's handle that in the next post :)









No comments:

Post a Comment