Why is my method not found? - objective-c

In my h file I have
+(CCRenderTexture*) createStroke: (CCLabelTTF*) label
size:(float)size
color:(ccColor3B)cor;
In my m file I implemented this method and use it like
CCRenderTexture* stroke = [self createStroke:pause size:3 color:ccBLACK];
But it gives me a warning "method not found". Why?

Since the +createStroke is a class method, you can't call it on self. You should instead send that message to the CCRenderTexture class.
So, in your case, if self is of the CCRenderTexture type, you could just replace it with self.class. (So that when you will subclass, the overridden method will be called by the superclass)
If it is not, write something like:
CCRenderTexture* stroke = [CCRenderTexture createStroke:pause size:3 color:ccBLACK];

plus means it is a class method, so you need to use the Class Name instead of an instance of that class: [ClassName createStroke:pause size:3 color:ccBLACK]
You probably want to have an instance method, so put a minus instead of plus in your declaration.
Here is some more info on this topic: What is the difference between class and instance methods?

Related

Is it possible to pass a selector or a method signature as a parameter in Objective-C?

As my title states, I'm wondering if I can pass a method signature or an #selector as a parameter? I'm asking because I'm creating a framework and I want to be able to pass instances of a certain class within it a method name.
You can pass the selector itself of use the name of the method as a string:
- (void)myMethod:(SEL)selector
{
[aClass performSelector:selector];
}
or
NSString *myMethodName = NSStringFromSelector(#selector(myMethod));
NSLog(#"The name of the method is: %#", myMethodName);
Actually, you cannot not pass a selector to a method.
In Objective-C, every method gets two implicit arguments, passed as normal parameters: The instance pointer self and the target selector _cmd. They are present in each and every method. The _cmd parameter is of type SEL. It is used by the runtime to look up the method implementation (this is the core of objc's dynamism).
You can, of course, add additional parameter of SEL type.

Calling a static method on a class

Given a method like the one below, that returns a Class...
-(Class)getClass
{
return [MyAwesomeClass class];
}
...how do I call a static method on that class? I tried this, but it didn't work...
Class theClass = [anInstance getClass];
[theClass someStaticMethod];
How should I call a static method on theClass?
Edit to add:
It seems I was doing the right thing, and something else was causing the crash. Now I need to figure out how to get rid of the warning that the method someStaticMethod isn't found. What should I cast theClass to?
You do it exactly the way you've written it, assuming the class in question responds to someStaticMethod.
If it isn't working correctly, then one of these is most likely the case:
You don't have the class you think
The class doesn't respond to the message
You declared the method incorrectly
You haven't imported the header where the method is declared
The method itself is buggy
It is an old question but i answer it for completeness. if you use id instead of Class it will work
id theClass = [anInstance getClass];
[theClass someStaticMethod];
Compiler will be happy with this dynamic typing but you must be sure that Class will respond to +someStaticMethod or it will crash at runtime

call method in different from #selector in Objective-C

How do we call a method which is in classB from #selector tag of classA.??
Can i do it in this way??
[tis_obj authenticate:self action:#selector([classB method]:)
accName:#"BOOK" User:#"User"];
Is there a possibility to call a method of different class form#selector tag?? or should the method be always in same class?
Thank You.
No you can't. To call a -[classB method:], the authenticate: parameter must have a classB instance, e.g.
classB* b = [[clasB alloc] init];
[tis_obj authenticate:b action:#selector(method:) …];
self.b = b;
[b release];
It looks like you want tis_obj to use the method selector on classB. I'm not sure what tis_obj is, but I see you're passing an argument self there. Perhaps what you're really looking for is:
[tis_obj authenticate:classB
action:#selector(method:)
accName:#"BOOK"
User:#"User"];
This will presumably mean that tis_obj will at one point perform the equivalent of [classB method:someArg].
A selector is just a name. The selector in the method call [someObject foo:5] is just foo:. It doesn't specify a method or a receiver, just the name.
What you pass to #selector() doesn't have a class name. A selector definition is simply a method name, so this will work:
[tis_obj authenticate:self action:#selector(method:)
accName:#"BOOK" User:#"User"];
(if "method:" is defined on your class of course)

Passing class method as selector problem

I want to build a selector from a class method.
I'm doing it this way:
NavigationTreeActionHandler* handler=[NavigationTreeActionHandler self];
NavigationTreeNode* bombsNode=new NavigationTreeNode("Bombs","bigbomb.tif"
,handler,#selector(BigBombButtonPressed:));
I need to pass to NavigationTreeNode the target and the selector to the target method.
I try to get the target using the self property of the class object (Don't know if htis is the correct way to do it). Then I get the selector for the class method I want to call on the class.
Everything compiles ok but it fails when I use:
[[handler class] instanceMethodSignatureForSelector:selector];
I get a nil and don't really know why... could anybody help please?
A few suggestions:
[NavigationTreeActionHandler self] will work fine to get the class object, but I would declare handler as type id instead of NavigationTreeActionHandler*, because it's not a reference to an instance that type
[handler class] is redundant; handler is already the class object.
instanceMethodSignatureForSelector: is only going to return nil if handler does not implement the selector. Verify your spelling etc., and try throwing in an NSLog to verify what you're receiving:
NSLog("handler = %# sel = %#", handler, NSStringFromSelector(selector));
But I'm unclear on what you're trying to do with instanceMethodSignatureForSelector: in the first place. If you're just trying to call the class method, wouldn't [handler performSelector:selector]; do what you want?
It's likely you're using code that assumes that calling the method class will get an object's class, and thus uses [[handler class] instanceMethodSignatureForSelector:selector] to get the method signature for the selector on the object handler. While that works for normal objects, that does not work for class objects, because of the different meaning of the class method on class objects, since the class method +class overrides the instance method -class, and +class simply returns the object it's called on, instead of the class it's an instance of (a meta-class).
The solution is that you don't even need to get the class at all, as there is a method you can call on an instance to get its method signature:
[handler methodSignatureForSelector:selector]
This is a much shorter and simpler way of doing what was intended, and also works for class objects too.

Overriding / Swizzling methods from an existing shared delegate

Is it possible to override ONLY CERTAIN functions from an exisiting delegate, without ourself being a delegate totally?
I tried replacing the target IMP with mine, didn't work :'(
More detail:
+[SomeClass sharedDelegate]
-[sharedDelegate targetMethodToBeOverridden:Arg:] //OUR method needs to be called, not this
Method *targetMethod; // targetMethodToBeOverridden identified by class_copymethodlist magic
targetMethod->method_imp = [self methodForSelector:#selector(overriddenDelegateMethod:Arg:)];
NOT WORKING! My Method is not being called :(
You probably shouldn't be manipulating the Method struct directly. Use the runtime function instead. You'll need to #import the runtime header, but there's a nice method in there called method_setImplementation. It'll work something like this:
id targetObject = [SomeClass sharedDelegate];
Method methodToModify = class_getInstanceMethod([targetObject class], #selector(replaceMe:argument:));
IMP newImplementation = [self methodForSelector:#selector(overriddenDelegateMethod:Arg:)];
method_setImplementation(methodToModify, newImplementation);
This may not work for your specific case, since class_getInstanceMethod might not return the Method for a method defined by an adopted protocol, but this is the "proper" way to swizzle Method IMPs.