17

I need help debugging my class. I am getting an error so bizarre that I couldn't find anything similar, so I'm just going to put down most of my code.

//Tab.h
#import <UIKit/UIKit.h>
@class Tab;
@protocol TabDelegateDataSource <NSObject>
@required
-(void)removeTab:(Tab *)tab;
@end

@interface Tab : UIView
{
     id <TabDelegateDataSource> __strong _delegate;
}

@property(strong) id <TabDelegateDataSource> delegate;

-(void)removeTab;

@end

//  Tab.m
#import "Tab.h"
@implementation Tab
@synthesize delegate = _delegate;
-(void)removeTab
{
    [self.delegate removeTab:self];//Error here saying: No known instance method for selector 'removeTab:'  
}

@end
jscs
  • 63,694
  • 13
  • 151
  • 195
Jordan Medlock
  • 807
  • 1
  • 8
  • 21
  • 1
    Out of curiosity, what would happen if you replace `self.delegate` with `_delegate` on the offending line? – Sergey Kalinichenko Dec 05 '11 at 15:36
  • Does your delegate actually have a method `removeTab`? This error message is implying it doesn't. Try debugging and inspecting self.delegate, and make sure it is what you expect, and that it has a `removeTab` method. – WilHall Dec 05 '11 at 15:37
  • 1
    the problem is not in the code you have posted. I copied it to a new project and it compiles without errors and warnings – Matthias Bauch Dec 05 '11 at 15:39
  • Please post the console error message. – zaph Dec 05 '11 at 15:49
  • [link](http://stackoverflow.com/questions/9579337/self-delegate-respondstoselector-does-not-compile) and [link](http://stackoverflow.com/questions/7941051/cannot-use-respondstoselector-using-arc-on-mac) have the answer. It has to do with NSObject – Roselle Tanner Aug 07 '14 at 07:43

9 Answers9

16

I can now recreate and fix this error at will.

Make sure that the .h header where this is defined ...

@protocol TabDelegateDataSource <NSObject>
-(void)removeTab:(Tab *)tab;
@end

... is included wherever you plan to use the delegate, e.g. somewhere at the top of the .m source that includes this:

[self.delegate removeTab:self]

If the compiler has only seen a forward definition of TabDelegateDataSource like this:

@protocol TabDelegateDataSource;

You'll get the error:

error: no known instance method for selector 'removeTab:'

and not the more expected forward definition related error

dpjanes
  • 5,745
  • 3
  • 25
  • 30
8

I think that it was a stupid problem with Xcode I restarted the app a couple of times and it ended up working out.

Jordan Medlock
  • 807
  • 1
  • 8
  • 21
4

You should always check your delegate this way, before calling a method, even with required protocol methods:

if( self.delegate != nil && [ self.delegate respondsToSelector: @selector( removeTab: ) ]
{
    /* Call delegate method... */
}

Doing so even for required methods adds an extra-safety, as this check is made at runtime.
Someone may ignore or disable the compiler warnings, or fool the compiler with type-casts.

For instance:

UILabel * label        = [ [ UILabel alloc ] initWithFrame: CGRectZero ];
someTableView.delegate = ( id < UITableViewDelegate > )label;

Also, you may want to use performSelector for the actual method call:

[ self.delegate performSelector: @selector( removeTab: ) withObject: self ];
frin
  • 4,474
  • 3
  • 31
  • 23
Macmade
  • 52,708
  • 13
  • 106
  • 123
  • 7
    I don't see why this should be necessary for methods that are defined as required in the protocol. The compiler will show a warning if a required method is not implemented. – Matthias Bauch Dec 05 '11 at 15:45
  • 1
    @Macmade What is the rational for preferring `performSelector` over a method call? – zaph Dec 05 '11 at 15:47
  • @fluchtpunkt This is an extra safety, so you don't rely on compiler settings. See my edit, which explain the reason of the runtime check. – Macmade Dec 05 '11 at 16:09
  • 3
    I get your point. But if I do something like a typecast to the wrong thing I would prefer a crash to silent malfunction. It's required for a reason. If the rest of the code works correctly without the required method it should have been declared @optional ^^ – Matthias Bauch Dec 05 '11 at 16:14
  • @fluchtpunkt Sure... Then simply do the check at runtime, for the extra safety, and throw an exception if it fails for a required protocol method. I know it may seem stupid, as the compiler should check this. But when you work with other people, it might get handy, as you don't control the way they code. : ) – Macmade Dec 05 '11 at 16:19
2

Make sure you haven't incorrectly declared the delegate property in the interface (probably by copying and pasting from another file). For example:

@protocol SomeDelegate

...

@end

@interface SomeClass

...

@property (nonatomic, retain) id<DifferentDelegate>delegate; 


@end

The above line will cause the "No known instance method for selector..." because of mismatch with the indtended protocol , probably a copy and paste error. Furthermore, it is likely overriding the correct reference to from a DIFFERENT class where it actually belongs, far away from this line of code, making it hard to spot.

Correct the above declaring your property with the intended protocol:

@property (nonatomic, retain) id<SomeDelegate>delegate;
Noah Dyer
  • 407
  • 5
  • 10
2

My problem was that I missed to declare <NSObject> in Protocol.

@protocol CustomProtocol <NSObject>
- (void)doSomethingWithSize:(CGSize)size;
@end
atulkhatri
  • 10,896
  • 3
  • 53
  • 89
1

Someone might needed,

SEL selector = NSSelectorFromString(@"removeTab");

if([self.delegate respondsToSelector:selector]) {
    objc_msgSend(self.delegate, selector);
}

Note: Don't forget this, #import <objc/message.h>

Arun
  • 476
  • 4
  • 6
1

Try to rename the delegate to others like delegateForTab.

Your class Tab is subclassing UIView, so self.delegate's self class is also a subclass of the UIView. UIView may has its own delegate(it inherits from UIResponder, and deep from NSObject), and it has not the -(void)removeTab method. Just my personal guess.
My solution is to rename it(not find the answer whether it can be subclassed either yet).

Suggestion for using delegate: You should implement the protocol and use the delegate in other view controllers, not in the same class that you declare it. :)

Kjuly
  • 34,476
  • 22
  • 104
  • 118
  • Good practice, but UIView does not have a delegate. So this won't help unfortunately... : ) – Macmade Dec 05 '11 at 19:03
  • @Macmade, thank you for your advice! I have happen met this issue before:I created a class that inherit from UINavigationController, resulted with same error, and I solved it by renaming the `delegate`. Just now, I refer to the SDK, the UIView doesn't have its delegate, it's right. :) However, It inherits from `UIResponder`, and deep from `NSObject`. `NSObject` has its protocol & delegate. So I think `[self.delegate removeTab:self];`'s `self` is just a NSObject. I'm not sure whether this is a true reason. Just my personal guess. :p – Kjuly Dec 06 '11 at 03:35
0

I import my appdelegate.h and error resolved...

Gaurav
  • 8,227
  • 4
  • 34
  • 55
0

This error is not a compiler error, isn't it? Because I have no compiler errors with your code here.

So if this is a runtime error, have you declared <TabDelegateDataSource> in your delegate classes like this:

@interface SomeClass : UIView <TabDelegateDataSource>

If you did so, the compiler should be warning you if your instance method can't be found.

Or maybe you should also post the code of your delegate class for more informations.

P.S. The delegate should not be __strong. You'd better use __unsafe_unretained instead.

xuzhe
  • 5,100
  • 22
  • 28