views:

208

answers:

4

I have a method as an NSString *. If it exists, I want to call it, and if not, do nothing.

SEL eventSelector = NSSelectorFromString(eventSelectorStr);
if ([delegate respondsToSelector:eventSelector]) {
    [delegate performSelector:eventSelector];
    [delegate adapterDidFinishAdRequest:self];
}
else {
    // Does not implement selector
}

This code does not work, since NSSelectorFromString will register the string as a selector, so respondsToSelector:eventSelector will cause a crash because the selector is actually invalid.

+3  A: 

Why do you say that that doesn't work? This is the most common way to implement invoking optional delegate methods. I've never had an issue with that construct not working.

Dave DeLong
For instance, if `eventSelectorStr` is `"fn1"`, and I implement `fn1` in the delegate, everything works fine. However, if `eventSelectorStr` is `"fn2"`, and that is not implemented, the code will cause a crash because `NSSelectorFromString` will register the string as a method and try to call it.
Justin
NSSelectorFromString does NOT try to call it. This has always worked for me too.
progrmr
`NSSelectorFromString` does not try to call it, but the next line in the code, `[delegate respondsToSelector:eventSelector]`, will cause the crash.
Justin
Then eventSelector is probably 0. NSSelectorFromString returns (SEL)0 if it is given a nil or if it can't convert the NSString to UTF-8. Are you giving it a valid string in eventSelectorStr?
progrmr
I like that - sounds plausible.
Paul Lynch
+1  A: 

Try checking for eventSelector != nil before using it.

drawnonward
`eventSelector` is never nil, as `NSSelectorFromString` will register the string as a selector and return that value.
Justin
eventSelector can be nil, read the NSSelectorFromString description.
progrmr
Not in my case. Read the comments, please.
Justin
+1  A: 

Let's clear up some confusion.

NSSelectorFromString() will generate a valid selector from the string, and will not crash in doing so. respondsToSelector: will validly determine if the delegate implements that method or not, without crashing. It is true that if you call performSelector: with a selector that the delegate doesn't implement it will cause a crash.

However, that isn't the situation here. The code is valid. If you have a crash in this code, I would check the error message and look instead to adapterDidFinishAdRequest:.

Paul Lynch
A: 

It took me a while to understand this as well. The key insights are that a selector reference is basically just a dressed-up C string, and that it doesn't 'belong' to any particular class or object. When the NSSelectorFromString() documentation says that the selector is 'registered', it just means that a dressed-up C string is 'blessed' (my term) for use as a selector within the Objective-C runtime.

Here's the section on the return value for NSSelectorFromString() from Apple's documentation:

Return Value

The selector named by aSelectorName. If aSelectorName is nil, or cannot be converted to UTF-8 (this should be only due to insufficient memory), returns (SEL)0.

Reading it carefully shows that the only situations which can cause (SEL)0 to be returned are if your string was nil or if you ran out of memory.

Tim Knauf