Problem with Code


#1

For some (probably obvious) reason, I’m getting errors when trying to get the code from Chapter 6 to work.

On the line NSInteger row = [_tableView selectedRow]; in the .m file below, I get: "Receiver type ‘NSScrollView’ for instance message does not declare a method with selectedRow’

I have other errors as well, but they’re all related to NSScrollView.

Suggestions would be welcomed.

Thanks.

  • m

====================================

My AppDeleate.h method is this:

#import <Cocoa/Cocoa.h>

@interface AppDelegate : NSObject <NSApplicationDelegate, NSSpeechSynthesizerDelegate>

{
    NSArray * _voices;
    NSSpeechSynthesizer *_speechSynth;
}
@property (weak) IBOutlet NSScrollView *tableView;

@property (assign) IBOutlet NSWindow *window;
@property (weak) IBOutlet NSTextField *textField;
@property (weak) IBOutlet NSButton *stopButton;
@property (weak) IBOutlet NSButton *speakButton;

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

@end

And, my .m file is this:


#import "AppDelegate.h"

@implementation AppDelegate

@synthesize tableView = _tableView;
@synthesize test = _test;
@synthesize window = _window;
@synthesize textField = _textField;  // compiler will automatically create getter and setter for this field.
@synthesize stopButton = _stopButton;
@synthesize speakButton = _speakButton;

-(id)init
{
    self = [super init];
    if (self)    
    {
        //logs can help the beginner understand what is happening and
        //hunt down bugs.
        NSLog(@"init");
        
        // create an instance of NSSpeechSynthesizer
        // with the default voice
        _speechSynth = [[NSSpeechSynthesizer alloc] initWithVoice:nil];
        
        [_speechSynth setDelegate:self];  // set the delegate if the speech synthesizer.
        
        // initialize array
        _voices = [NSSpeechSynthesizer availableVoices];
        
    }
    return self;
}


- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
    // Insert code here to initialize your application
}


- (IBAction)sayIt:(id)sender 
{
    NSString *string = [_textField stringValue];
    
    // is the string zero length?
    if ([string length] == 0)
    {
        NSLog(@"string from %@ is zero-length", _textField);
        return;
    }
    [_speechSynth startSpeakingString:string];
    NSLog(@"Have started to say %@", string);
    
    // enable stop button
    [_stopButton setEnabled:YES];
    [_speakButton setEnabled:NO];
    [_tableView setEnabled: NO];
}

- (IBAction)stopIt:(id)sender 
{
 
    NSLog(@"Stopping");
    [_speechSynth stopSpeaking];
     
}

// log a message when synthesizer is finished speaking
-(void) speechSynthesizer:(NSSpeechSynthesizer *)sender didFinishSpeaking:(BOOL)finishedSpeaking
{
    NSLog(@"finishedSpeaking = %d", finishedSpeaking);
    
    // reset buttons
    [_stopButton setEnabled:NO];
    [_speakButton setEnabled:YES];
}

// implement required methods for delegate
-(NSInteger) numberOfRowsInTableView:(NSTableView *) tv
{
    return (NSInteger)[_voices count];
}
    
-(id)tableView:(NSTableView *) tv
  objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
{
    NSString *v = [_voices objectAtIndex:row];
    // just return the name of the voice instead of the whole ".com.apple.speeach.synthezier.voice.Fred"
    NSDictionary *dict = [NSSpeechSynthesizer attributesForVoice:v];
    return [dict objectForKey:NSVoiceName];
    
}    
// implement complete.

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

-(void) awakeFromNib
{
    // when the table view appears on the screen, the default voice shoudl be selected
    NSString *defaultVoice = [NSSpeechSynthesizer defaultVoice];
    NSInteger defaultRow   = [_voices indexOfObject:defaultVoice];
    NSIndexSet *indicies   = [NSIndexSet indexSetWithIndex:defaultRow];
    [_tableView selectRowIndexes: indicies byExtendingSelection:NO];
    [_tableView scrollRowToVisible:defaultRow];
    
}
@end


#2

morkus,

It looks like you created an outlet called tableView which is connected to the NSScrollView. The tableView outlet should be connected to the NSTableView. I’m guessing that when you used the Assistant Editor to create the outlet, you accidentally had the scroll view selected.

To fix this:

  1. Edit the .h file and change “NSScrollView *tableView” to “NSTableView *tableView”.
  2. In MainMenu.xib, select the table view by clicking twice on it (remember to check the jump bar; the rightmost item will say Table View when you’ve got it selected. You can also use the interface builder dock when it is expanded to select the table view.
  3. Control-drag to connect the table view to the tableView outlet on the app delegate.

Adam


#3

Thanks. The most difficult to follow portion of the book is where you’re making connections in Interface Builder. I don’t mean that as a criticism, just that it’s the most difficult to convey.

In any case, this is closer, but I’m now getting a runtime error on this line of code:

2011-11-29 06:47:37.629 Speakline[4124:707] init
2011-11-29 06:47:37.850 Speakline[4124:707] -[NSScrollView selectRowIndexes:byExtendingSelection:]: unrecognized selector sent to instance 0x1004178b0

The .h file now has the code below, but the runtime error above is still referencing NSScrollView.

?

I tried a “clean” and a rebuild, but that didn’t seem to help.

I clicked the “voices” table twice so that the top jumpbar said “Table View” (to the right of Scroll View - Table View). Then I control clicked the table and dragged to the app Delegate and clicked the delegate connection.

Sure there’s something simple here.

Even the local variable says the _tableView is still an NSScrollView (_tableView NSScrollView * 0x100136c90)

Thanks again in advance.

  • m
#import <Cocoa/Cocoa.h>

@interface AppDelegate : NSObject <NSApplicationDelegate, NSSpeechSynthesizerDelegate>

{
    NSArray * _voices;
    NSSpeechSynthesizer *_speechSynth;
}
@property (weak) IBOutlet NSTableView *tableView;

@property (assign) IBOutlet NSWindow *window;
@property (weak) IBOutlet NSTextField *textField;
@property (weak) IBOutlet NSButton *stopButton;
@property (weak) IBOutlet NSButton *speakButton;

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

@end

#4

Looks like the scroll view is still connected to the tableView outlet. If you right click on the App Delegate in the dock, you will see the connections panel, and you should see the tableView->Scroll View connection there. Hit the X to break the connection and try making the connection again.

Yeah, it does take a while to get used to making connections in IB, and being sure you’ve got the thing you want selected. You’ll get there, though!

Adam


#5

This may help.

When I have trouble getting the proper item “picked” by clicking on it in the Interface Builder (IB), I use the dock in expanded mode to pick the right item. If you click the right arrow circle near the bottom of the “dock” in IB it will expand the dock from icons to actual named items. Then you can (using the drill down method) get to the exact item you want “picked”. It will highlight each item on the screen as you choose them in the dock. In some, not all, cases you can control drag from the selected item in the dock, but to me, it makes more sense to always drag from/to the graphical item instead of its text version in the dock.


#6

Wow, great tip, thank you! Yes, expanding the object dock is quite helpful.

Thanks to both on this thread, I got the helper “application” working so I can now hear all the different voices. There’s a lot of code there.

What really helped me with your book, Adam, was that you showed Java code next to Objective C code. That simple comparison immensely helped me make the translation of how methods get called with parameters and such.

Cocoa seems like a huge framework, but hey, I’m only starting chapter 9. :slight_smile:

Thanks again for all the replies!!!

-m

P.S. I’m wondering why XCODE doesn’t automatically, or with perhaps a right mouse or menu click, generate the “.m” implementation stubs for you. Eclipse does that and just about every other Java IDE I’ve used. Perhaps there’s a reason why XCODE doesn’t offer this or I just haven’t figured out how to do it…


#7

Glad to hear the Java references helped! Cocoa is not small, but the good news is that there are a few core concepts that are used throughout. Once you understand those ideas (MVC, delegates/helper objects, KVC, etc.) you will be ready to spot those patterns in new parts of Cocoa that you encounter, and you’ll have some idea of how to use them right off the bat.

Historically, Xcode hasn’t done a lot automatically. It’s grown a lot with version 4. One of the new features in Xcode 4 was the ability to use the assistant editor to drag and create outlets and actions in the source, which creates the stubs for you. Hopefully this is the start of a trend and we’ll continue to see more of these conveniences. There are some third party tools out there, such as Accessorizer, that help with the more mundane Xcode tasks

Adam