I've been working through the exercises in a book recommended here on stackoverflow, however I've run into a problem and after three days of banging my head on the wall, I think I need some help.
I'm working through the "Speakline" exercise where we add a TableView to the interface and the table will display the "voices" that you can choose for the text to speech aspect of the program.
I am having two problems that I can't seem to get to the bottom of:
I get the following error: * Illegal NSTableView data source ().  Must implement numberOfRowsInTableView: and tableView:objectValueForTableColumn:row:
The tableView that is supposed to display the voices comes up blank
I have a feeling that both of these problems are related.
I'm including my interface code here:
#import <Cocoa/Cocoa.h>
@interface AppController : NSObject <NSSpeechSynthesizerDelegate, NSTableViewDelegate>
{
    IBOutlet NSTextField *textField;
    NSSpeechSynthesizer *speechSynth;
    IBOutlet NSButton *stopButton;
    IBOutlet NSButton *startButton;
    IBOutlet NSTableView *tableView;
    NSArray *voiceList;
}
- (IBAction)sayIt:(id)sender;
- (IBAction)stopIt:(id)sender;
@end
And my implementation code here:
#import "AppController.h"
@implementation AppController
- (id)init
{
    [super init];
    //Log to help me understand what is happening
    NSLog(@"init");
    speechSynth = [[NSSpeechSynthesizer alloc] initWithVoice:nil];
    [speechSynth setDelegate:self];
    voiceList = [[NSSpeechSynthesizer availableVoices] retain];
    return self;
}
- (IBAction)sayIt:(id)sender
{
    NSString *string = [[textField stringValue] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
    //Is the string zero-length?
    if([string length] == 0) {
        NSLog(@"String from %@ is a string with a length of %d.", textField, [string length]);
        [speechSynth startSpeakingString:@"Please enter a phrase first."];
    }
    [speechSynth startSpeakingString:string];
    NSLog(@"Started to say: %@", string);
    [stopButton setEnabled:YES];
    [startButton setEnabled:NO];
}
- (IBAction)stopIt:(id)sender
{
    NSLog(@"Stopping...");
    [speechSynth stopSpeaking];
}
- (void) speechSynthesizer:(NSSpeechSynthesizer *)sender didFinishSpeaking:(BOOL)complete
{
    NSLog(@"Complete = %d", complete);
    [stopButton setEnabled:NO];
    [startButton setEnabled:YES];
}
- (NSInteger)numberOfRowsInTableView:(NSTableView *)aTableView
{
    return [voiceList count];
}
- (id)tableView: (NSTableView *)tv objecValueForTableColumn: (NSTableColumn *)tableColumn
            row:(NSInteger)row
{
    NSString *v = [voiceList objectAtIndex:row];
    NSLog(@"v = %@",v);
    NSDictionary *dict = [NSSpeechSynthesizer attributesForVoice:v];
    return [dict objectForKey:NSVoiceName];
}
/*
- (BOOL)respondsToSelector:(SEL)aSelector
{
    NSString *methodName = NSStringFromSelector(aSelector);
    NSLog(@"respondsToSelector: %@", methodName);
    return [super respondsToSelector:aSelector];
}
*/
@end
Hopefully, you guys can see something obvious that I've missed.
Thank you!