jason dancks
jason dancks

Reputation: 1142

Objective-C/Cocoa/XCode Newbie: How to receive Notifications?

I couldn't get an example from a cocoa programming book to work (part of the problem I think is XCode is out of date). It didn't mention anything special I had to do to receive notifications from NSTableView other than make the appropriate connections in IB. The app is a program with a NSTextField for User input and when a button is clicked an instance of NSSpeechSynthesizer will speak the line entered. Im supposed to be able to switch speaking voices by selecting a row on the table view. I can click on, the app technically works but I can't change the default speaking voice by clicking a row on NSTableView on the GUI:

GUI inpterface

appdelegate.h:

#import <Cocoa/Cocoa.h>

@interface AppDelegate : NSObject <NSApplicationDelegate,NSSpeechSynthesizerDelegate,NSTableViewDelegate>
{
    NSArray *_voices;
    NSSpeechSynthesizer *_speechSynth;
}

@property (assign) IBOutlet NSWindow *window;
@property (weak) IBOutlet NSTextField *textField;
@property (assign) IBOutlet NSTextField *text;

@property (assign) IBOutlet NSButton *_speakButton;
@property (assign) IBOutlet NSButton *_stopButton;

@property (assign) IBOutlet NSTableView *table;

-(IBAction)sayIt:(id)sender;
-(IBAction)stopIt:(id)sender;

@end

appdelegate.m:

#import "AppDelegate.h"

@implementation AppDelegate

@synthesize window = _window;
@synthesize textField = _textField;
@synthesize text = _text;
@synthesize _speakButton;
@synthesize _stopButton;

@synthesize table;

-(void)speechSynthesizer:(NSSpeechSynthesizer *)sender didFinishSpeaking:(BOOL)finishedSpeaking
{
    NSLog(@"finishedSpeaking=%d",finishedSpeaking);
    [_speakButton setEnabled:YES];
    [_stopButton setEnabled:NO];
    [table setEnabled:YES];
}

-(id)init
{
    NSLog(@"init called");
    self = [super init];
    if (self)
    {
        NSLog(@"init");
        _speechSynth = [[NSSpeechSynthesizer  alloc] initWithVoice:nil];
        [_speechSynth setDelegate:self];
        [_text setStringValue:@""];
        _voices = [NSSpeechSynthesizer availableVoices];
    }

    //I added this line myself as I was trying to figure it out
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(tableViewSelectionDidChange:) name:@"MyNotification" object:table];
    return self;
}
-(IBAction)sayIt:(id)sender
{
    NSString *string = [_textField stringValue];
    if([string length]==0)
    {
        NSLog(@"string from %@ is of zero-length",_textField);
        return;
    }
    [_speechSynth startSpeakingString:string];
    [_text setStringValue:[_speechSynth voice]];
    ...
}
-(IBAction)stopIt:(id)sender
{
    NSLog(@"stopping");
    ...
}
-(NSInteger)numberOfRowsInTableView:(NSTableView *)tv
{
    return (NSInteger)[_voices count];
}
-(id)tableView:(NSTableView *)tv
objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
{
    NSString *v = [_voices objectAtIndex:row];
    NSDictionary *dict =[NSSpeechSynthesizer attributesForVoice:v];
    return [dict objectForKey:NSVoiceName];
}

-(void)tableViewSelectionDidChange:(NSNotification *)notification
{
    NSInteger row = [table selectedRow];
    if(row==-1) return;
    NSString *selectedVoice = [_voices objectAtIndex:row];
    [_speechSynth setVoice:selectedVoice];
    NSLog(@"new voice = %@",selectedVoice);
}

-(void)awakeFromNib
{
    NSLog(@"awakeFromNib");
    NSString *defaultVoice = [NSSpeechSynthesizer defaultVoice];
    NSInteger defaultRow = [_voices indexOfObject:defaultVoice];
    NSIndexSet *indices = [NSIndexSet indexSetWithIndex:defaultRow];
    [table selectRowIndexes:indices byExtendingSelection:NO];
    [table scrollRowToVisible:defaultRow];
}
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
    NSLog(@"Appdidfinishlaunching called");
}

@end

I'm guessing I got this way wrong. I just need someone to point me in the right direction of how this is supposed to work.

Upvotes: 1

Views: 678

Answers (1)

matt
matt

Reputation: 535231

There are several possible sources of error here.

  • You might have forgotten to hook the table view in the nib to the app delegate as its delegate.

  • You might have forgotten to hook the app delegate in the nib to the text field as its textField.

    (There are other possibilities (having to do with hooking things up in the nib) but I won't list all of them...)

  • If your goal really is to get the selection message as a notification, then this line is wrong:

    [[NSNotificationCenter defaultCenter] 
      addObserver:self selector:@selector(tableViewSelectionDidChange:) 
      name:@"MyNotification" object:table];
    

    The name of this notification is not @"MyNotification"; it is NSTableViewSelectionDidChangeNotification.

Upvotes: 1

Related Questions