Search code examples
objective-cuisegmentedcontrolunrecognized-selector

Confusion about unrecognized selector sent to instance


Sooooo, I keep getting this error:

Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[CardGameViewController matchModeSegmentedControl:]: unrecognized selector sent to instance 0x8c84da0'

I've been doing a bunch of Googling, but I'm pretty confused about what exactly the problem is. Here's all the code that contains anything involving the Segmented Control (the source of all my current woes).

@interface CardGameViewController ()
 ...
@property (nonatomic, weak) IBOutlet UISegmentedControl *matchModeSegmentedControl;
 ...
@end

@implementation CardGameViewController

...

- (CardMatchingGame *)game
{
    self.matchModeSegmentedControl.enabled = YES;
    if (!_game) {
        _game = [[CardMatchingGame alloc]
                 initWithCardCount:[self.cardButtons count]
                 withDeck:[self newPlayingCardDeck]
                 withSegmentedControllerValue:self.gameMatchMode];
    }
    return _game;
}

...

- (IBAction)touchCardButton:(UIButton *)sender
{
    self.matchModeSegmentedControl.enabled = NO;
    int cardIndex = [self.cardButtons indexOfObject:sender];
    Card *card = [self.game cardAtIndex:cardIndex];

    if (!card.isChosen) {
        [self.game chooseCardAtIndex:cardIndex];

        [self updateUI];
        [self.game compareSelectedCards:cardIndex];
        [self performSelector:@selector(updateUI)
                   withObject:nil afterDelay:2.0];
    }
}

...

- (IBAction)matchModeSegmentedControlIndexChanged:(UISegmentedControl *)sender
{
    self.gameMatchMode = sender.selectedSegmentIndex;
    [self.game setValueMatchMode:self.gameMatchMode];
}

Let me know if you need any more information. Thanks!

EDIT: Full stack trace below...sorry about the formatting. I just copied and pasted.

 2014-12-02 23:54:44.549 Matchismo[15252:60b] -[CardGameViewController
 matchModeSegmentedControl:]: unrecognized selector sent to instance
 0x8c454f0 (lldb) bt
 * thread #1: tid = 0x1a48c4, 0x015748b9 libobjc.A.dylib`objc_exception_throw, queue = 'com.apple.main-thread',
 stop reason = breakpoint 1.1
frame #0: 0x015748b9 libobjc.A.dylib`objc_exception_throw
frame #1: 0x01892243 CoreFoundation`-[NSObject(NSObject) doesNotRecognizeSelector:] + 275
frame #2: 0x017e550b CoreFoundation`___forwarding___ + 1019
frame #3: 0x017e50ee CoreFoundation`__forwarding_prep_0___ + 14
frame #4: 0x0158682b libobjc.A.dylib`-[NSObject performSelector:withObject:] + 70
frame #5: 0x002363b9 UIKit`-[UIApplication sendAction:to:from:forEvent:] + 108
frame #6: 0x00236345 UIKit`-[UIApplication sendAction:toTarget:fromSender:forEvent:] + 61
frame #7: 0x00337bd1 UIKit`-[UIControl sendAction:to:forEvent:] + 66
frame #8: 0x00337fc6 UIKit`-[UIControl _sendActionsForEvents:withEvent:] + 577
frame #9: 0x00337c06 UIKit`-[UIControl sendActionsForControlEvents:] + 48
frame #10: 0x003a6222 UIKit`-[UISegmentedControl _setSelectedSegmentIndex:notify:animate:] + 598
frame #11: 0x003a8573 UIKit`-[UISegmentedControl touchesEnded:withEvent:] + 175
frame #12: 0x00275ddd UIKit`-[UIWindow _sendTouchesForEvent:] + 852
frame #13: 0x002769d1 UIKit`-[UIWindow sendEvent:] + 1117
frame #14: 0x002485f2 UIKit`-[UIApplication sendEvent:] + 242
frame #15: 0x00232353 UIKit`_UIApplicationHandleEventQueue + 11455
frame #16: 0x0177e77f CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 15
frame #17: 0x0177e10b CoreFoundation`__CFRunLoopDoSources0 + 235
frame #18: 0x0179b1ae CoreFoundation`__CFRunLoopRun + 910
frame #19: 0x0179a9d3 CoreFoundation`CFRunLoopRunSpecific + 467
frame #20: 0x0179a7eb CoreFoundation`CFRunLoopRunInMode + 123
frame #21: 0x037e95ee GraphicsServices`GSEventRunModal + 192
frame #22: 0x037e942b GraphicsServices`GSEventRun + 104
frame #23: 0x00234f9b UIKit`UIApplicationMain + 1225
frame #24: 0x00003edd Matchismo`main(argc=1, argv=0xbfffede4) + 141 at main.m:16 (lldb)

With an All Exceptions breakpoint, XCode directs me to this:

#import "CardGameAppDelegate.h"

int main(int argc, char * argv[])
{
    @autoreleasepool {
        return UIApplicationMain(argc, argv, nil, NSStringFromClass([CardGameAppDelegate class]));
    }
}

Solution

  • The error is saying that something sent the message -matchModeSegmentedControl: to an instance of CardGameViewController. Note the colon on that message name.

    Your class has a property matchModeSegmentedControl whose getter is a method named after the property (-matchModeSegmentedControl). Note, no colon in that method name.

    Your class also has an action method named -matchModeSegmentedControlIndexChanged:. As is normal for action methods, that method takes an argument and thus has a colon. Also, the name is quite similar to the property.

    I suspect you have connected a segmented control's action to the wrong action method (one which doesn't actually exist). It's trying to invoke an action named -matchModeSegmentedControl: when it should be invoking the action named -matchModeSegmentedControlIndexChanged:. That may have been set up in the NIB. Maybe you changed the name of the action method at some point but didn't update the connection in the NIB. The NIB should be showing you a warning, which I would expect would also appear when you build.