Chapter 9: Perform Selector and Delayed Perform

I’ve come across selectors several times in the sample programs I’ve studied, and even used them occasionally when writing my own code, mostly for messages sent so my code can act as a delegate for printing and saving.

For my example code, I decided to make GUI-based program, with a little “animation” of a count-down shown in the app’s window. The count-down started at 10 seconds, and updated every tenth of a second; at the end it displayed an end-of-count message.

The template for a GUI app now includes an application delegate object in the MainMenu.xib, as well as creating header and implementation files for the delegate’s class, so I didn’t even have to create any new files.

Create a new Cocoa Application in Xcode. Look under the Classes item in the Groups and Folders pane, and you’ll see that Xcode has provided an application delegate class based on your chosen file name; since I named my original program BlogExample, the new one was BlogExampleAppDelegate. This is where you’ll place your animation code. Before doing that, let’s set up the app’s window.

Open MainMenu.xib in Interface Builder, and add a text label to your window. Widen it so it can show all the text that your program will create in it. It doesn’t matter what text you have in it now, since the program will change it.

Now go back to Xcode, and open the app delegate class’s header file. Add an outlet for the text label and an int for the count. Create properties for them as shown.

//
//  BlogExampleAppDelegate.h
//  BlogExample
//
//  Created by Norm Hecht on 4/23/10.
//  Copyright 2010 Scamp Dog Software. All rights reserved.
//

#import <Cocoa/Cocoa.h>

@interface BlogExampleAppDelegate : NSObject <NSApplicationDelegate> {
    NSWindow *window;
	NSTextField *label;
	int count;
}

@property (assign) IBOutlet NSWindow *window;
@property (assign) IBOutlet NSTextField *label;
@property (readwrite) int count;

@end

Next, open the implementation file and add the @synthesize statements for the new properties. You will be adding code to the applicationDidFinishLaunching: delegate method.

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
	count = 100; // initialize the counter
	NSString *countString = [NSString stringWithFormat:@"%d.%d to go", 
							 count/10, count % 10];
	[label setStringValue:countString]; // Change the label

	// Send the selector for the update method to the delegate class itself, 
        // and have it execute after a 0.1 second delay.  The method doesn't 
        // need to carry any data with it, so withObject gets a nil.  
	[self performSelector:@selector(adjustCount) withObject:nil afterDelay:0.1];
}

Now add the code for the adjustCount method. It needs to change the label, and set itself up to run again (maybe).

- (void)adjustCount {
	count--;
	if (count > 0) {
		NSString *countString = [NSString stringWithFormat:@"Only %d.%d seconds to go!", 
								 count/10, count % 10];
		[label setStringValue:countString];
		[self performSelector:@selector(adjustCount) withObject:nil afterDelay:0.1];
	} else {
		[label setStringValue:@"Ding Ding Ding!"];
	}
}

More aggressive developers may want to change the final message to “ka-boom!” Now head back to IB to connect the outlet and save the nib. Return to Xcode and compile. You should see the time-to-go displayed in the app’s window, and see the final message when it finishes.

Advertisements
This entry was posted in Uncategorized. Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s