UINavigationController as a Modal View

On my current iPhone project I need to display an Options view that will behave as a navigation controller with a main table view and associated subviews. I was able to accomplish this using various sources out there but feel the need to compile it all in one place.

For the purposes of this example I have a main view controller and a secondary view controller. The main view controller is the primary view controller for the application and the secondary view controller will be the root view controller of the navigation controller. Let’s also assume that I have a NIB file for the secondary view controller. In my application I wish to show a UINavigationController modally as the help section.

Changes to MainViewController.h:

#import "SecondaryViewController.h"

@class SecondaryViewController;

@interface MainViewController : UIViewController { SecondaryViewController *secondaryViewController; UINavigationController *navController;}

- (IBAction)navigateToSecondaryViewController;


All I’ve done here is tell the main view controller where to find the secondary view controller and then assign it as a delegate to the secondaryViewDelegate protocol which will be defined in SecondaryViewController.h. I also created a quick IBAction method to tie to any button on the view.

Changes to MainViewController.m:

(IBAction) navigateToSecondaryViewController { if (secondaryViewController == nil) {  informationTableViewController = [[SecondaryViewController alloc]                    initWithNibName:@"SecondaryViewController"                     bundle:[NSBundle mainBundle]];  secondaryViewController.delegate = self; }

 if (navController == nil) {  navController = [[UINavigationController alloc]        initWithRootViewController:secondaryViewController]; }

 [self presentModalViewController:navController animated:YES];


- (void)closeSecondaryViewController { [self dismissModalViewControllerAnimated:YES];}

- (void)dealloc { if (secondaryViewController != nil) {  [secondaryViewController release]; }  if (navController != nil) {  [navController release]; }        [super dealloc];}

In my navigateToSecondaryViewController method I now initialize my view controllers if necessary. Assign the secondary view controller (which contains the information I want to display) to the navigation controller and display it modally. The closeSecondaryViewController method is the delegate method from the SecondaryViewController class which we will define next.



@protocol SecondaryViewDelegate 

- (void)closeSecondaryViewController;


@interface SecondaryViewController : UIViewController { id delegate;}

@property (assign) id delegate;

Define the header for the secondary view controller, define a protocol with a single method and create a delegate property for calling the delegate method. 


#import “SecondaryViewController.h”

@implementation SecondaryViewController

@synthesize delegate;

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {    if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) {  self.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;    }    return self;}

- (void)viewDidLoad {    [super viewDidLoad];

 UIBarButtonItem *closeButton = [[UIBarButtonItem alloc] init]; closeButton.title = @"Done"; = self; = UIBarButtonItemStyleDone; [closeButton setAction:@selector(closeButtonTouch)];

 self.navigationItem.title = @"Options";

 self.navigationItem.rightBarButtonItem = closeButton; [closeButton release];}

- (void)closeButtonTouch { [delegate closeSecondaryViewController];}

- (void)dealloc {    [super dealloc];}

In the initWithNibName method I've just modified the animation style for displaying this view modally. The default is to slide in from the bottom of the screen. In the viewDidLoad method I just create a button to close the view, add it to the navigation item for the view controller and assign it a selector method. The selector method calls the delegate method that will close the view.



Ripple Effect on the iPhone

So on this iPhone App I am working on I am trying to create an effect on a image such that if you touch any part of the image the app will simulate a water ripple effect out from the touch point. After a few hours of research it became clear to me that I would have no choice but to attempt this effect using OpenGL ES which I had been trying to avoid. However I discovered this excellent tutorial complete with project template that made things a lot easier:

Using this tutorial I was able to create my texture map and apply an image to it. From there it just became a matter for coding the ripple effect. Here is what I came up with:

-(void)update:(float)time{ int i;  for( i = 0; i < (80*120*6); i++ ) {  int index = i * 3;  float *vertArray = (float *)originalVertices;

  Vertex3D v = { vertArray[index], vertArray[index+1], vertArray[index+2] };
CGPoint vect = CGPointMake(position.x - v.x, position.y - v.y);  CGFloat r = sqrtf(vect.x*vect.x + vect.y*vect.y);

  if ( r < radius )  {   r = radius - r;   CGFloat rate = powf( r / radius, 2);   v.z += (sinf( time*(CGFloat)M_PI*waves*2 + r * 0.1f) * amplitude * amplitudeRate * rate );

  float *vertArray2 = (float *)vertices;  vertArray2[index] = v.x;  vertArray2[index+1] = v.y;  vertArray2[index+2] = v.z; }


I still have a ways to go to finish it but here’s what is going on so far. First I’m looking through all of my vertices in my texture map. My texture map is 80×120 and for each point I am actually am creating 6 vertices to render a square. I know this can be optimized using GL_TRIANGLE_STRIPs but I’m not there yet. Then I create the vector and distance (r) from the touch point.

Assuming I am within the radius of the ripple I defined (which I could make dynamic down the road based on touch time) I then calculate the new depth (z) of the vertex I am on using the amplitude and other values that were set previously. After that I just update the vertices to render with the new values and it’s good to go.

I still have to handle multiple touches and other factors but what I ended up with so far is pretty cool. I’ll post a video of the effect once I’m done.


To Retain or Not To Retain?

Ran into an interesting thing doing iPhone development yesterday.

I needed to pause an NSTimer object (which, of course, you can’t). So to work around this I was storing the start time of the timer in a class level NSDate object using the following.

In the header file:

NSDate *startTime;

and in the class file:

startTime = [NSDate date];

I did under the assumption that using the [NSDate date] static method would behave similar to the timer method I was using to start the timer. However when I would try to access the startTime object later it was deemed out of scope by the debugger.

I changed my line of code to look like this instead:

startTime = [[NSDate date] retain];

Basically I’m now explicitly retaining the value of startTime (which also means I have to release it later). What I don’t like is the inconsistency with the static method used to create a timer. I don’t need to explicitly retain the NSTimer object so why do I need to explicitly retain the NSDate object?