我正在关注“Mac OS X 的 Cocoa 编程”的示例,它解释了如何实现 NSTableView 的协议。
我试着按照书上说的做所有事情,但可能我错过了一些东西。
有一个 NSSpeechSynthesizer 和一个文本域,每次用户按下“speak”按钮,文本域的内容由语音合成器说出。还有一个 NSTableView 包含所有声音的列表,用户可以选择他更喜欢的声音。
这是代码:
界面:
#import <Cocoa/Cocoa.h>
@interface SpeakLineAppDelegate : NSObject <NSApplicationDelegate, NSSpeechSynthesizerDelegate, NSTableViewDelegate, NSTableViewDataSource>
{
@private
NSWindow *window;
NSTextField *textField;
NSTableView *tableView;
NSButton *speakButton;
NSSpeechSynthesizer* ss;
NSButtonCell *stopButton;
NSArray* voices;
}
@property (assign) IBOutlet NSWindow *window;
@property (assign) IBOutlet NSTextField *textField;
@property (assign) IBOutlet NSTableView *tableView;
@property (assign) IBOutlet NSButton *speakButton;
- (IBAction)speak:(id)sender;
- (IBAction)stop:(id)sender;
@property (assign) IBOutlet NSButtonCell *stopButton;
@end
执行:
#import "SpeakLineAppDelegate.h"
@implementation SpeakLineAppDelegate
@synthesize stopButton;
@synthesize textField;
@synthesize tableView;
@synthesize speakButton;
@synthesize window;
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
// Insert code here to initialize your application
}
- (id) init
{
self=[super init];
if(self)
{
NSLog(@"init method called");
ss=[[NSSpeechSynthesizer alloc]initWithVoice:nil];
[ss setDelegate: self];
voices=[NSSpeechSynthesizer availableVoices];
}
return self;
}
- (IBAction)speak:(id)sender
{
NSString* str=[textField stringValue];
if([str length]>0)
{
[ss startSpeakingString: str];
[stopButton setEnabled: YES];
[speakButton setEnabled: NO];
}
else
{
NSLog(@"The string has length zero");
}
}
- (IBAction)stop:(id)sender
{
[ss stopSpeaking];
}
- (void) speechSynthesizer:(NSSpeechSynthesizer *)sender didFinishSpeaking: (BOOL)finishedSpeaking
{
NSLog(@"Has finished speaking");
[stopButton setEnabled: NO];
[speakButton setEnabled: YES];
}
- (NSInteger) numberOfRowsInTableView:(NSTableView *)tableView
{
return [voices count];
}
- (id) tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
{
NSString* str=[voices objectAtIndex: row];
NSDictionary* dict=[NSSpeechSynthesizer attributesForVoice: str];
return [dict objectForKey: NSVoiceName];
}
- (void)tableViewSelectionDidChange:(NSNotification *)notification
{
NSInteger row=[tableView selectedRow];
if(row!=-1)
{
NSString* str=[voices objectAtIndex: row];
[ss setVoice: str];
NSLog(@"New voice: %@",str);
}
}
@end
我还在 xib 文件中完成了以下操作:
-我已将 NSTableView 的选项“数据源”和“委托”链接到 SpeakLineAppDelegate(我的应用程序的文件名)。
IBOutlet textField 与 xib 文件中的 NSTextField 链接,speak 和 stop 也是为 xib 文件中的按钮设置的操作。
NSTableView 是 IBOutlet “tableView”,这个也是在 xib 文件中链接的。
问题:此时我得到 EXC_BAD_ACCESS:
- (id) tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
{
NSString* str=[voices objectAtIndex: row]; // here I get the exception
NSDictionary* dict=[NSSpeechSynthesizer attributesForVoice: str];
return [dict objectForKey: NSVoiceName];
}
我无法弄清楚这个异常的原因,因为声音是在 init 方法中分配的。
使用gdb,如果我在抛出异常时尝试打印行的值,它会打印为零,所以我真的不知道我的代码有什么问题。