Cocoa Programming for Mac OS X - Aaron Hillegass [37]
Many classes in the Cocoa framework have an instance variable called delegate. You can set the delegate outlet to point to a helper object. In the documentation for the class, the delegate methods are clearly described. For example, the NSSpeechSynthesizer class has the following delegate methods:
- (void)speechSynthesizer:(NSSpeechSynthesizer *)sender
didFinishSpeaking:(BOOL)finishedSpeaking;
- (void)speechSynthesizer:(NSSpeechSynthesizer *)sender
willSpeakWord:(NSRange)characterRange
ofString:(NSString *)string;
- (void)speechSynthesizer:(NSSpeechSynthesizer *)sender
willSpeakPhoneme:(short)phonemeOpcode;
The Apple programmer who wrote NSSpeechSynthesizer put these hooks in. He is Michael Knight. You are KITT.
Of the three messages that the speech synthesizer sends to its delegate, you care about only the first one: speechSynthesizer:didFinishSpeaking:.
In your application, you will make the SpeakLineAppDelegate the delegate of the speech synthesizer and implement speechSynthesizer:didFinish-Speaking:. The method will be called automatically when the utterance is complete. The new object diagram is shown in Figure 6.1.
Figure 6.1. New SpeakLine Object Diagram
Note that you do not have to implement any of the other delegate methods. The implemented methods will be called; the unimplemented ones will be ignored. Also note that the first argument is always the object that is sending the message—in this case, the speech synthesizer.
In SpeechLineAppDelegate.h, change the SpeechLineAppDelegate class declaration:
@interface SpeakLineAppDelegate : NSObject
This change tells the compiler that SpeakLineAppDelegate conforms to the NSSpeechSynthesizerDelegate protocol. We will cover protocols in Chapter 10. Now, in SpeakLineAppDelegate.m, set the delegate outlet of the speech synthesizer: - (id)init { self = [super init]; if (self) { // Logs can help the beginner understand what // is happening and hunt down bugs. NSLog(@"init"); // Create a new instance of NSSpeechSynthesizer // with the default voice. _speechSynth = [[NSSpeechSynthesizer alloc] initWithVoice:nil]; [_speechSynth setDelegate:self]; } return self; } Next, add the delegate method. For now, just log a message: - (void)speechSynthesizer:(NSSpeechSynthesizer *)sender didFinishSpeaking:(BOOL)finishedSpeaking { NSLog(@"finishedSpeaking = %d", finishedSpeaking); } Build and run the application. Note that the delegate method is called if you click the Stop button or if the utterance plays all the way to the end. (finished-Speaking is YES only if the utterance plays to the end.) To enable and disable the Stop and Start buttons, you will need outlets for them. We will use the Interface Builder editor and the Assistant Editor as we did in Chapter 5 for the textField outlet to create and connect startButton and stopButton outlets in SpeakLineAppDelegate.h. Open MainMenu.xib and enable the Assistant Editor. Control-drag from the Stop button to the SpeakLineAppDelegate class interface to create a new outlet. Name the outlet stopButton, as shown in Figure 6.2. Also, Control-drag from the Speak button to create a speakButton outlet. Figure 6.2. Set stopButton Outlet The Stop button should be disabled when it first appears on screen, so select the button and disable it in the Attributes Inspector as shown in Figure 6.3. Save the NIB file. Figure 6.3. Disable Stop Button In Xcode, edit the SpeakLineAppDelegate.m file to properly enable and disable the button. In sayIt:, enable the button: - (IBAction)sayIt:(id)sender { NSString *string = [_textField stringValue]; // Is the string zero-length? if ([string length] == 0) { NSLog(@"string from %@ is of zero-length", _textField); return; } [_speechSynth