0

I have a class method (+) that takes an argument of type NSString. What I want to do with that class method is to return information from another class method, there are many different class methods that return different things, I don't want to use a switch or if-statement but something like this:

return [self "ClassMethodName"];

I know how to do it with a @selector() but it seems like I cant use it in a class method. Is there another way to do what I want?

Anil Natha
  • 2,538
  • 6
  • 30
  • 39
Arbitur
  • 36,899
  • 22
  • 86
  • 123

2 Answers2

2

If you're doing it from a class method, self is the class object so you can do this:

+ (id)myClassMethod {
    return [self performSelector:NSSelectorFromString(@"ClassMethodName")];
}

If you're doing it from an instance method, you have to ask yourself for your class:

- (id)myInstanceMethod {
    return [self.class performSelector:NSSelectorFromString(@"ClassMethodName")];
}

Of course you can use @selector(ClassMethodName) if ClassMethodName is known at compile time, but I assume you don't actually know the selector name until runtime.

Note that Xcode doesn't know that Class objects are instances of NSObject, so it won't autocomplete performSelector: for you in these cases.

rob mayoff
  • 342,380
  • 53
  • 730
  • 766
  • If `self` is a class, it will run the class method. – rob mayoff Dec 06 '13 at 20:57
  • Oh wow, xcode didn*t suggest it when I typed it when the method was a class method, but it did when I changed it into an instance method... I had to just type the whole thing. darn you xcode. – Arbitur Dec 06 '13 at 21:00
  • Xcode doesn't know that `Class` is a subclass of `NSObject`. It can be annoying. – rob mayoff Dec 06 '13 at 21:00
  • Hm It give me a warning "PermformSelector may cause a leak because its selector is unknown" Why does it give me that? I use the NSSelectorFromString() :S – Arbitur Dec 06 '13 at 21:03
  • See [this answer](http://stackoverflow.com/a/11895530/77567) for two ways to suppress the warning. – rob mayoff Dec 06 '13 at 21:05
  • 2
    clang warns you because it doesn't know for sure what method you're calling. If the method returns an object that the caller is expected to release, clang (ARC) won't take care of releasing it and you'll leak memory. So don't use `performSelector:` to call methods (like `copy` and `alloc`) that return an object with a +1 retain count. – rob mayoff Dec 06 '13 at 21:09
  • Actually, `performSelector` is supposed to use with selector's of methods with return type of `void`. However, methods that return `int` or some pointer type won't won't crash if you call them via `performSelector` due to architecture specialties (for example, on x86 they will return value in `eax`, on armv7 maybe `r0`, i'm not sure), just leak an objects. The problem begins if you `performSelector` with selector with return type of some struct like CGSize or CGRect - the stack will be corrupted and you'll get your app crashd. For nonvoid methods use `NSInvocation` instead of `performSelector` – Petro Korienev Dec 06 '13 at 21:31
  • 1
    `performSelector:` is declared to return `id`, not `void`. Furthermore, the [documentation of `performSelector:`](https://developer.apple.com/library/ios/documentation/cocoa/reference/foundation/Protocols/NSObject_Protocol/Reference/NSObject.html#//apple_ref/occ/intfm/NSObject/performSelector:) says it returns “An object that is the result of the message”, not `void`. It also says “For methods that return anything other than an object, use NSInvocation.” – rob mayoff Dec 06 '13 at 22:28
  • Also, the implementation of `performSelector:` is [part of Apple's open source Objective-C runtime](http://www.opensource.apple.com/source/objc4/objc4-551.1/runtime/NSObject.mm), and is essentially `return ((id(*)(id, SEL))objc_msgSend)(self, sel);`. Thus it is clearly intended to be used with messages that return `id`, not `void`. – rob mayoff Dec 06 '13 at 22:32
  • @robmayoff: "Note that Xcode doesn't know that Class is a subclass of NSObject" There is no class named `Class` – newacct Dec 08 '13 at 21:34
  • @newacct True. I have modified my answer. – rob mayoff Dec 09 '13 at 01:48
  • @robmayoff: "Note that Xcode doesn't know that Class objects are instances of NSObject" That's only true for classes that inherit from `NSObject`. – newacct Dec 09 '13 at 07:15
1

You can actually, since classes are objects themselves.

SEL selector = NSSelectorFromString(@"ClassMethodName");    

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
[self performSelector:selector];
#pragma clang diagnostic pop

The pragma lines are needed to silence the compiler warning "PerformSelector may cause a leak because its selector is unknown" (see this question for details).

Community
  • 1
  • 1
DrummerB
  • 38,675
  • 12
  • 100
  • 138