0

我正在关注“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,如果我在抛出异常时尝试打印行的值,它会打印为零,所以我真的不知道我的代码有什么问题。

4

0 回答 0