Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Beginning iOS5 Development.pdf
Скачиваний:
7
Добавлен:
09.05.2015
Размер:
15.6 Mб
Скачать

210

CHAPTER 7: Tab Bars and Pickers

forComponent:(NSInteger)component reusingView:(UIView *)view {

This method returns one of the image views from one of the five arrays. To do that, we once again create an NSString with the name of one of the arrays. Because component is zero-indexed, we add one to it, which gives us a value between column1 and column5 and which will correspond to the component for which the picker is requesting data.

NSString *arrayName = [[NSString alloc] initWithFormat:@"column%d", component+1];

Once we have the name of the array to use, we retrieve that array using a method called valueForKey:, which is the counterpart to the setValue:forKey: method that we used in viewDidLoad. Using it is the same as calling the accessor method for the property you specify. So, calling valueForKey: and specifying "column1" is the same as using the column1 accessor method. Once we have the correct array for the component, we just return the image view from the array that corresponds to the selected row.

NSArray *array = [self valueForKey:arrayName]; return [array objectAtIndex:row];

}

Wow, take a deep breath. You got through all of it in one piece, and now you get to take it for a spin.

Final Details

Our game is rather fun, especially when you think about how little effort it took to build it. Now let’s improve it with a couple more tweaks. There are two things about this game right now that really bug us:

It’s so darn quiet. Slot machines aren’t quiet!

It tells us that we’ve won before the dials have finished spinning, which is a minor thing, but it does tend to eliminate the anticipation. To see this in action, run your application again. It is subtle, but the label really does appear before the wheels finish spinning.

The 07 Pickers/Custom Picker Sounds folder in the project archive that accompanies the book contains two sound files: crunch.wav and win.wav. Add this folder to your project’s Pickers folder. These are the sounds we’ll play when the users tap the Spin button and when they win, respectively.

To work with sounds, we’ll need access to the iOS Audio Toolbox classes. Insert this line at the top of BIDCustomPickerViewController.m:

#import <AudioToolbox/AudioToolbox.h>

Next, we need to add an outlet that will point to the button. While the wheels are spinning, we’re going to hide the button. We don’t want users tapping the button again until the current spin is all done. Add the following code to

BIDCustomPickerViewController.h:

www.it-ebooks.info

CHAPTER 7: Tab Bars and Pickers

211

#import <UIKit/UIKit.h>

@interface BIDCustomPickerViewController : UIViewController <UIPickerViewDataSource, UIPickerViewDelegate>

@property (strong, nonatomic) IBOutlet UIPickerView *picker; @property (strong, nonatomic) IBOutlet UILabel *winLabel; @property (strong, nonatomic) NSArray *column1;

@property (strong, nonatomic) NSArray *column2; @property (strong, nonatomic) NSArray *column3; @property (strong, nonatomic) NSArray *column4; @property (strong, nonatomic) NSArray *column5;

@property (strong, nonatomic) IBOutlet UIButton *button;

- (IBAction)spin;

@end

After you type that and save the file, click BIDCustomPickerViewController.xib to edit the nib. Once it’s open, control-drag from File’s Owner to the Spin button, and connect it to the new button outlet we just created. Save the nib.

Now, we need to do a few things in the implementation of our controller class. First, we need to synthesize the accessor and mutator for our new outlet. Open

BIDCustomPickerViewController.m and add the following line:

@implementation BIDCustomPickerViewController @synthesize picker;

@synthesize winLabel; @synthesize column1; @synthesize column2; @synthesize column3; @synthesize column4; @synthesize column5;

@synthesize button;

.

.

.

We also need a couple of methods added to our controller class. Add the following two methods to BIDCustomPickerViewController.m as the first two methods in the class:

-(void)showButton { self.button.hidden = NO;

}

-(void)playWinSound {

NSURL *soundURL = [[NSBundle mainBundle] URLForResource:@"win" withExtension:@"wav"];

SystemSoundID soundID;

AudioServicesCreateSystemSoundID((__bridge CFURLRef)soundURL, &soundID); AudioServicesPlaySystemSound(soundID);

winLabel.text = @"WINNING!";

[self performSelector:@selector(showButton) withObject:nil afterDelay:1.5];

}

www.it-ebooks.info

212

CHAPTER 7: Tab Bars and Pickers

The first method is used to show the button. As noted previously, we’re going to hide the button when the user taps it, because if the wheels are already spinning, there’s no point in letting them spin again until they’ve stopped.

The second method will be called when the user wins. The first line of this method asks the main bundle for the path to the sound called win.wav, just as we did when we loaded the property list for the Dependent picker view. Once we have the path to that resource, the next three lines of code load the sound file in and play it. Then we set the label to WINNING! and call the showButton method, but we call the showButton method in a special way using a method called performSelector:withObject:afterDelay:. This is a very handy method available to all objects. It lets you call the method some time in the future—in this case, one and a half seconds in the future—which will give the dials time to spin to their final locations before telling the user the result.

NOTE: You may have noticed something a bit odd about the way we called the AudioServicesCreateSystemSoundID function. That function takes a URL as its first parameter, but it doesn’t want an instance of NSURL. Instead, it wants a CFURLRef structure. Apple provides C interfaces to many common components—such as URLs, arrays, strings, and much more—via the Core Foundation framework. This allows even applications written entirely in C some access to the functionality that we normally use from Objective-C. The interesting thing is that these C components are “bridged” to their Objective-C counterparts, so that a CFURLRef is functionally equivalent to an NSURL pointer, for example. That means that certain kinds of objects created in Objective-C can be pushed over the bridge to use C APIs, and vice versa. This is accomplished by using a C language cast, putting the type you want your variable to be interpreted as inside parentheses before the variable name. Starting in iOS 5, with the use of ARC, the type name itself must be preceded by the keyword __bridge, which gives ARC a hint about how it should handle this Objective-C object as it passes into a C API call.

We also need to make some changes to the spin: method. We will write code to play a sound and to call the playerWon method if the player won. Make the following changes to the spin: method now:

- (IBAction)spin { BOOL win = NO; int numInRow = 1; int lastVal = -1;

for (int i = 0; i < 5; i++) {

int newValue = random() % [self.column1 count];

if (newValue == lastVal) numInRow++;

else

numInRow = 1;

lastVal = newValue;

[picker selectRow:newValue inComponent:i animated:YES]; [picker reloadComponent:i];

www.it-ebooks.info

CHAPTER 7: Tab Bars and Pickers

213

if (numInRow >= 3) win = YES;

}

self.button.hidden = YES;

NSString *path = [[NSBundle mainBundle] pathForResource:@"crunch" ofType:@"wav"];

SystemSoundID soundID; AudioServicesCreateSystemSoundID(

(__bridge CFURLRef)[NSURL fileURLWithPath:path], &soundID); AudioServicesPlaySystemSound (soundID);

if (win)

[self performSelector:@selector(playWinSound) withObject:nil

afterDelay:.5];

else

[self performSelector:@selector(showButton) withObject:nil

afterDelay:.5];

winLabel.text = @"";

if (win)

winLabel.text = @"WIN!";

else

winLabel.text = @"";

}

The first line of code we added hides the Spin button. The next four lines play a sound to let the player know they’ve spun the wheels. Then, instead of setting the label to WIN! as soon as we know the user has won, we do something tricky. We call one of the two methods we just created, but we do it after a delay using performSelector:afterDelay:. If the user won, we call our playerWon method half a second into the future, which will give time for the dials to spin into place; otherwise, we just wait a half a second and reenable the Spin button.

The only thing left to do is to release our button outlet, so make the following changes to your viewDidUnload method:

- (void)viewDidUnload { [super viewDidUnload];

//Release any retained subviews of the main view.

//e.g. self.myOutlet = nil;

self.picker = nil; self.winLabel = nil; self.column1 = nil; self.column2 = nil; self.column3 = nil; self.column4 = nil; self.column5 = nil; self.button = nil;

}

www.it-ebooks.info

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]