Just getting going with iPhone development and Objective-C.
Yesterday I was trying to addObserver for a notification in a view of mine, and I kept getting this error:
unrecognized selector sent to instance
I tracked it down to the fact that I needed to include the trailing colon to my selector argument:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(nameOfMySelector:) name:#"BBLocationServicesAreDisabled" object:nil];
Today, I thought I was clever because when setting up the action argument to a button, I remembered my mistake yesterday, and added the colon to the action argument. The action argument takes a #selector, just like the selector argument while setting up an observer for an NSNotification, so I figured I was doing the right thing.
However, with the following code:
[self.callToActionButton addTarget:self action:#selector(nameOfMySelector:) forControlEvents:UIControlEventTouchUpInside];
I get the exact same error:
unrecognized selector sent to instance
What gives? Why does one #selector require a trailing colon, and the other doesn't? What are the rules I should follow for when it should be included and when it should be left off, and why I can't I always just do one or the other?
Thanks!
As mentioned by boltClock, the character you are referring to is actually a colon. The difference between #selector(method) and #selector(method:) is the method signature. The 2nd variant expects a parameter to be passed.
#selector(method) would expect the method: -(void)method
#selector(method:) would expect the method: -(void)method:(id)someParameter
You seem to be missing one concept here: colon is, in some way, a part of the method name. E.g., method
-(IBAction) doIt:(id)sender;
has name doIt:. Thus, colon should be used to reference this method.
But this method doesn't have a colon at the end
-(IBAction) doItWithoutParameter;
Same goes for methods accepting multiple arguments, they have names like doItWithParam1:andParam2:
A selector represents a method name, and the number of colons in a selector matches the number of arguments in the corresponding method:
mySelector — no colon, no arguments, e.g. - (void)mySelector;, [self mySelector];
mySelectorWithFoo: — one colon, a single argument, e.g. - (void)mySelectorWithFoo:(Foo *)foo;, [self mySelectorWithFoo:someFoo];
mySelectorWithFoo:withBar: — two colons, two arguments, e.g. - (void)mySelectorWithFoo:(Foo *)foo bar:(Bar *)bar;, [self mySelectorWithFoo:someFoo bar:someBar];
and so forth.
It is also possible to have a selector without ‘naming’ the parameters. It’s not recommended since it’s not immediately clear what the parameters are:
mySelector:: — two colons, two arguments, e.g. - (void)mySelector:(Foo *)foo :(Bar *)bar;, [self mySelector:someFoo :someBar];
mySelector::: — three colons, three arguments, e.g. - (void)mySelector:(int)x :(int)y :(int)z;, [self mySelector:2 :3 :5];
The colon indicates that the method takes a parameter.
[someObject performSelector:#selector(doSomething:)] means that doSomething is expecting a parameter.
[someObject performSelector:#selector(doSomething)] means that doSomething doesn't need any parameters.
In your case:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(nameOfMySelector:) name:#"BBLocationServicesAreDisabled" object:nil];
- (void) nameOfMySelector: (NSNotification *) notification {
/* this method would require the semi-colon */
}
or in this case:
[self.callToActionButton addTarget:self action:#selector(nameOfMySelector:) forControlEvents:UIControlEventTouchUpInside];
- (void) nameOfMySelector: (id) sender {
/* this method would also require the semi-colon */
}
I think the problem is the missing parameter.
See this post: Objective-C: Calling selectors with multiple arguments (Great answers!)
Related
When my code gets to a certain point in execution, it needs to call a selector. Problem is, which selector to call, along with the object passed to it in performSelector, changes each time. The candidate selectors are all functions written ahead of time, but how can I convert from a variable (e.g.: NSString* or enum telling program which selector to call) to the name of the selector, without using a gigantic switch statement?
SEL selector = NSSelectorFromString(aSelectorName);
if ([self respondsToSelector: selector])
{
[self performSelector: selector];
}
I have an object (A) that needs to work as a proxy to an other object. there is also a condition that when verified should make the object work as nil.
I've implemented:
-(void)forwardInvocation:(NSInvocation *)anInvocation
{
if (condition)
[anInvocation invokeWithTarget:self.object];
else
[anInvocation invokeWithTarget:nil];
}
but it's not enough. when the condition is satisfied and a method is called on A unrecognized selector sent to instance is raised.
From the documentation on invoke in NSInvocation's class reference:
You must set the receiver’s target, selector, and argument values before calling this method.
If you haven't set target (or have set it to nil, which is basically the same thing), you shouldn't be invoking the invocation. If you want to mimic the behaviour of sending a message to nil, you can just return 0/nil - this is the default behaviour of objc_msgSend if the target is nil. If you're interested in seeing why this works, you can have a look here for an overview of objc_msgSend's implementation (fair warning, it's all in assembly).
This line of code works perfectly
[self explodeBomb:obj];
but if I replace it with the following line, I get an NSInvalidArgument Exception, with the reason being an unrecognized selector.
[self performSelector:#selector(explodeBomb) withObject:obj ];
The definition of the method is as follows:
-(void)explodeBomb:(SKNode *)bomb
I know, this has to be me not understanding something fundamental. But why I am able to call the method directly with no problems, but when I try to use the performSelector it blows up? For the record obj is defined as an ID. I tried changing the signature of explodeBomb to take an ID and then explicitly cast it inside the method, but that threw the same exception. Anyone know what the heck I am doing wrong?
Use : and write like below
[self performSelector:#selector(explodeBomb:) withObject:obj ];
Since your method explodeBomb has an argument so you have to specify :
I was looking into iOS NUI Framework source code. I spotted the following line of codes but I couldn't figured out how it worked
- (void)override_didMoveToWindow
{
if (!self.isNUIApplied) {
[self applyNUI];
}
[self override_didMoveToWindow];
}
Just to be clear, they swizzled out the original implementation of DidMoveToWindow with this method in order to apply the class/style at run time. What confused me was that the function above never caused any infinite loop.
This may help: http://darkdust.net/writings/objective-c/method-swizzling
The swizzled method is actually exchanged with the original. So when the original method is called the swizzled method has already exchanged the implementation. And calling the "swizzled method" override_didMoveToWindow method will call the original function.
Comment the line
//[self override_didMoveToWindow];
works for me
It looks like not a loop because it appears the author assumes that [self applyNUI] always changes the state so that self.isNUIApplied becomes == YES
I have gone down quite a few paths and wondered if someone could spot this right off:
I want to display a button when a text field is selected (hence the keyboard is loaded).
From what i've read NSNotificationCenter is one way to do this:
So in viewWillAppear I placed the following
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardDidAppear:) name:UIKeyboardWillShowNotification object:self.view.window];
for the destination (selector) i have:
-(void)keyboardDidAppear{
_button2.hidden = FALSE;
}
the program aborts to a crash dump (sure seems like there should be a better debugging path than this)
if I comment out the only line in keyboardDidAppear
// _button2.hidden = FALSE;
the program still aborts
so evidently the NSNotificationCenter is firing and is not tolerated for some reason
Any simplified help would be appreciated.
Seriously, the crash dump is all you get when theres an execution error? Is it all you need?
The problem is simple. You register the method keyboardDidAppear: but you supply a method named keyboardDidAppear. These are not the same (notice the colon).
Change one or the other (but not both).
Another solution would be to implement the UITextFieldDelegate method textFieldDidBeginEditing: and show the button when this is called.
You are trying to send a message to keyboardDidAppear: but you implemented keyboardDidAppear. The first method is a method taking a parameter, but you supplied a method taking no parameters, which of course is different.
Change either your method definition to
-(void)keyboardDidAppear:(NSNotification *)n {
_button2.hidden = NO; //Please stick to Obj-C semantics and use NO, as opposed to FALSE.
}
or the call to
#selector(keyboardDidAppear)