Converting a String to a "Method" - To be used in a Class Method call - objective-c

I'm familiar with NSSelectorFromString function with which we can create a new SEL from a string.
The problem is that I cannot use it to perform a Class Method call since the performSelector method works only with instances as its receiver.
I need something that may function like this:
NSString* colorName = colorsArray[num];
NSString* methodName = [NSString stringWithFormat:#"%#Color", colorName]; //will create blueColor or redColor, etc...
SEL colorMethod = NSSelectorFromString(methodName);
self.view.backgroundColor = [UIColor performSelector:colorMethod]; //this is not valid... since NSObject only has performSelector as an Instance method...
Is there another way to hold an on-the-run variable representing a Method that can function as a Class Method and can be created from an NSString?
Or a way to message a Class with a selector?

The problem is that I cannot use it to perform a Class Method call
since the performSelector method works only with instances as its
receiver.
This is wrong. What makes you think that the UIColor class object is not an "instance"? Class objects are objects, which means they are "instances" of some class. Class objects are instances of (some subclass of) their root class, which in the case of UIColor is NSObject. (In other words, the UIColor class objects is also an NSObject and supports all NSObject instance methods.)
If you want to understand how this works, every class object is an instance of a metaclass. Every class has its own metaclass, and metaclasses have inheritance following their classes (i.e. if A is superclass of B, then A's metaclass is superclass of B's metaclass). At the end, the metaclass of the root class inherits from the root class itself (so NSObject's metaclass inherits from NSObject). What this means is that class methods are inherited, and furthermore that the root class (in this case NSObject)'s instance methods are inherited as class methods by all classes with that root class.

just call performSelector on the class
#import <Foundation/Foundation.h>
#interface T : NSObject
+ (NSString*)foo;
+ (NSString*)redColor;
#end
#implementation T
+ (NSString*)foo {
return #"bar";
}
+ (NSString*)redColor {
return #"RED";
}
#end
int main(int argc, char *argv[]) {
#autoreleasepool {
id tclass = [T class];
NSLog(#"%#", [tclass performSelector:#selector(foo)]);
NSLog(#"%#", [tclass performSelector:#selector(redColor)]);
SEL sel = NSSelectorFromString(#"redColor");
NSLog(#"%#", [tclass performSelector:sel]);
}
}

You can also use NSInvocation:
SEL sel = NSSelectorFromString(#"whiteColor");
NSMethodSignature *sig = [UIColor methodSignatureForSelector:sel];
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:sig];
[invocation setSelector:sel];
[invocation setTarget:[UIColor class]];
CFTypeRef retVal;
[invocation invoke];
[invocation getReturnValue:&retVal];
NSLog(#"retVal: %#", retVal);

From Cocoa Fundamentals Guide (obsolete but this part is still valid):
The runtime system treats methods defined in the root class in a
special way. Instance methods defined in a root class can be performed
both by instances and by class objects. Therefore, all class objects
have access to the instance methods defined in the root class.
The Foundation framework provides two root classes: NSObject and NSProxy. NSObject has a method documented as – performSelector:, but because it is a root class, any subclass is able to use it as a class method. For example: both +[UIColor performSelector:] and -[UIColor performSelector:] work. The explanation at a runtime level is in newacct's answer.
One calls the class method and the other calls the instance method. Example:
#import <Foundation/Foundation.h>
#interface A : NSObject
#end
#implementation A
+(void) x { NSLog(#"class method"); }
-(void) x { NSLog(#"instance method"); }
#end
int main(int argc, char *argv[]) {
#autoreleasepool {
[A performSelector:#selector(x)];
[[A new] performSelector:#selector(x)];
}
}
Prints
class method
instance method

Related

Finding out isMemberOf equivalent with Objc run-time Class type

When I have a reference to Objc run-time's Class type, how can I find out if this class refers to an NSObject?
Class aClass = [NSArray class];
Class aSuperClass = class_getSuperclass(aClass); // Points to NSObject
// What's the best way to test at runtime whether aSuperClass is pointing
// to an NSObject type?
BOOL isNSObjectClass = [aSuperClass isMemberOfClass:[NSObject class]]; // This returns NO
You're confusing classes and metaclasses.
Boiling it down, this:
[[NSObject class] isMemberOfClass:[NSObject class]]
... correctly returns NO because the metaclass that contains information about NSObject is not itself an instance of NSObject. Conversely, this:
[[NSObject new] isMemberOfClass:[NSObject class]]
... would return YES because you've created an instance of NSObject rather than inspecting the metaclass. The metaclass descends from NSObject but is not itself an instance of NSObject.
So what exactly is it that you're trying to test? Whether a class descends from NSObject, without having an instance of that class? If so you probably need manually to walk the isa chain. E.g.
- (BOOL)class:(Class)someClass isSubclassOf:(Class)class
{
while(someClass)
{
if(someClass == class) break;
someClass = class_getSuperclass(someClass);
}
return !!someClass;
}
You should see:
[self class:[NSObject class] isSubclassOf:[NSObject class]] // YES
[self class:[NSProxy class] isSubclassOf:[NSObject class]] // NO
If you don't mind the namespace implications, possibly even:
#interface NSObject (ObjectIndicator)
#end
#implementation NSObject (ObjectIndicator)
+ (void)someOldMethodOrOther {};
#end
And then:
[NSProxy respondsToSelector:#selector(someOldMethodOrOther)];
You can compare the Class instances:
BOOL isNSObjectClass = aSuperClass == [NSObject class];

Objective-C Class Method

My header class looks like:
#import "Card.h"
#interface PlayingCard : Card
#property (strong, nonatomic) NSString *suit;
#property (nonatomic) NSUInteger rank;
+ (NSArray *) validSuits;
+ (NSUInteger) maxRank;
#end
And my implementation:
#implementation PlayingCard
+ (NSArray *) validSuits
{
return #[#"♥︎", #"♣︎", #"♦︎", #"♠︎"];
}
+ (NSArray *) rankStrings
{
return #[#"?", #"1", #"2", #"3", #"4"];
}
- (void)setSuit:(NSString *)suit
{
if ([[PlayingCard validSuits] containsObject:suit])
{
_suit = suit;
}
}
- (NSString *)suit
{
return _suit ? _suit : #"?"; // if suit !nil return suit, else return ? string.
}
+ (NSUInteger)maxRank
{
return [[self rankStrings] count] - 1;
}
#end
So I understand that any method with a + means it's a Class method.
My question is, why must I use [PlayingCard classMethod] e.g. [PlayingCard validSuits] in the setSuit method whereas I can use [self classMethod] e.g. [self rankStrings] in the maxRank method?
I'm assuming it's something to do with the maxRank method being a class method whereas setSuit isn't. But could it be because setSuit is a setter?
I really don't know, I can't visualise what's going on here. I've only just started my foray into Objective-C and am coming from a Java background.
I have realised I can substitute PlayingCard in for self in the maxRank method without any error messages, however substituting self in for PlayingCard in the setSuit method gives me an error saying
No visible #interface for 'PlayingCard' declares the selector for 'validSuits'
Any explanation as to why this is the case and what's going on would be great. Thanks!
The meaning of self in methods
Every Objective-C method receives an implicit self argument. Instance methods receive the instance, while class methods receive the class object (remember: classes are objects).
If you want to send a class method, the compiler lets you use two types of syntax:
[ClassName classMethod]
[classObjectPtr classMethod]
The first syntax is used in [PlayingCard maxRank]. Here, the target is (explicitly) the PlayingCard class.
A class method already has a class object as a target for sending class methods: the self argument. So they can use [self classMethod] to send other class methods.
Why sending a message to self in class methods?
The advantage of the latter is that the class is not explicitly named. This makes it possible to override class methods in subclasses and call them from base classes.
You basically get the same dynamic method dispatch as with instance methods. This is actually a nice feature of Objective-C not present in Java or C++.
Instance methods would use the dynamic version by accessing their class and sending the message to that:
- (void)setSuit:(NSString *)suit
{
if ([[[self class] validSuits] containsObject:suit])
{
_suit = suit;
}
}
Now an imaginary subclass of PlayingCard could override the class method validSuits and implicitly alter the behavior of setSuit:.
self can be an instance or a class depending on the type of method declared.
- (void)setSuit: is an instance method, thus self is an instance inside this method declaration.
+ (NSUInteger)maxRank is a class method, thus self is a class inside inside this method declaration.
+ (void)classMethod;
- (void)instanceMethod;
- (void)setSuit
{ // self is an instance here
[self classMethod]; // warning, class method sent to instance
[self instanceMethod]; // works, instance method sent to instance
}
+ (NSUInteger)maxRank
{ // self is a class here
[self classMethod]; // works, class method sent to class
[self instanceMethod]; // warning, instance method sent to class
}
You tried to called a "class method" on self inside an instance method where self in an "instance".
In a class method, self refers to the class (it refers to an object that represents the class that obj-c runtime creates for you), so you can use it to call class level method.
In an instance method, self refers to the instance. If you want to call class level method in an instance method, you need to use the class name instead.
Java analogy of obj-c class methods is the static method. Java's this keyword is similar to self, except it can't be used to refer to a class.
setSuit is an instance method, and validSuits is a class method. However, both maxRank and rankStrings are class methods. Class methods are basically the same as static methods in C++

Difference between class methods and instance methods?

I always confusing to when i used of instance method and class method in programming. Please tell me difference between instance method and class methods and advantages of one another.
All the other answers seem to have been caught out by the incorrect tag that has now been fixed.
In Objective-C, an instance method is a method that is invoked when a message is sent to an instance of a class. So, for instance:
id foo = [[MyClass alloc] init];
[foo someMethod];
// ^^^^^^^^^^ This message invokes an instance method.
In Objective-C, classes are themselves objects and a class method is simply a method that is invoked when a message is sent to a class object. i.e.
[MyClass someMethod];
// ^^^^^^^^^^ This message invokes a class method.
Note that, in the above examples the selector is the same, but because in one case it is sent to an instance of MyClass and in the other case it is sent to MyClass, different methods are invoked. In the interface declaration, you might see:
#interface MyClass : NSObject
{
}
+(id) someMethod; // declaration of class method
-(id) someMethod; // declaration of instance method
#end
and in the implementation
#implementation MyClass
+(id) someMethod
{
// Here self is the class object
}
-(id) someMethod
{
// here self is an instance of the class
}
#end
Edit
Sorry, missed out the second part. There are no advantages or disadvantages as such. It would be like asking what is the difference between while and if and what are the advantages of one over the other. It's sort of meaningless because they are designed for different purposes.
The most common use of class methods is to obtain an instance when you need one. +alloc is a class method which gives you a new uninitialised instance. NSString has loads of class methods to give you new strings, e.g. +stringWithForma
Another common use is to obtain a singleton e.g.
+(MyClass*) myUniqueObject
{
static MyUniqueObject* theObject = nil;
if (theObject == nil)
{
theObject = [[MyClass alloc] init];
}
return theObject;
}
The above method would also work as an instance method, since theObject is static. However, the semantics are clearer if you make it a class method and you don't have to first create an instance.
If we don't want to create the object of class then we use the class method
if we want call the method through object of a class then we use the instance method
I don't know if we can talk of any advantage, this is rather a matter of what you are implementing.
Instance methods apply on instances of classes, so they need an object to be applied on and can access their caller's members:
Foo bar;
bar.instanceMethod();
On the other hand class methods apply on the whole class, they don't rely on any object:
Foo::classMethod();
Static member functions are informally called class methods (incorrectly). In C++ there are no methods, there are member functions.
Read up on the static keyword, that pretty much covers it.
MSDN:
http://msdn.microsoft.com/en-us/library/s1sb61xd.aspx
Google search:
http://www.google.ch/search?aq=f&sourceid=chrome&ie=UTF-8&q=static+keyword+c%2B%2B
Class methods are used with classes but instance methods are used with objects of that class i.e instance
//Class method example
className *objectName = [[className alloc]init];
[objectName methodName];
//Instance method example
[className methodName];
instance methods use an instance of a class, whereas a class method can be used with just the class name. + sign is used before the Class Method where as single desh (-) is used before the instance variable.
#interface MyClass : NSObject
+ (void)aClassMethod;
- (void)anInstanceMethod;
#end
They could also be used like so,
[MyClass aClassMethod];
MyClass *object = [[MyClass alloc] init];
[object anInstanceMethod];
or another example is:
[
NSString string]; //class method
NSString *mystring = [NSString alloc]init];
[mystring changeText]; //instance Method
Like most of the other answers have said, instance methods use an instance of a class, whereas a class method can be used with just the class name. In Objective-C they are defined thusly:
#interface MyClass : NSObject
+ (void)aClassMethod;
- (void)anInstanceMethod;
#end
They could then be used like so:
// class methods must be called on the class itself
[MyClass aClassMethod];
// instance method require an instance of the class
MyClass *object = [[MyClass alloc] init];
[object anInstanceMethod];
Some real world examples of class methods are the convenience methods on many Foundation classes like NSString's +stringWithFormat: or NSArray's +arrayWithArray:. An instance method would be NSArray's -count method.

Dynamically invoke a class method in Objective C

Suppose I have Objective C interface SomeClass which has a class method called someMethod:
#interface SomeClass : NSObject {
}
+ (id)someMethod;
#end
In some other interface I want to have a helper method that would dynamically invoke someMethod on a class like this:
[someOtherObject invokeSelector:#selector(someMethod) forClass:[SomeClass class];
What should be the implementation for invokeSelector? Is it possible at all?
- (void)invokeSelector:(SEL)aSelector forClass:(Class)aClass {
// ???
}
Instead of:
[someOtherObject invokeSelector:#selector(someMethod) forClass:[SomeClass class];
call:
[[SomeClass class] performSelector:#selector(someMethod)];
Example (using GNUstep ...)
file A.h
#import <Foundation/Foundation.h>
#interface A : NSObject {}
- (NSString *)description;
+ (NSString *)action;
#end
file A.m
#import <Foundation/Foundation.h>
#import "A.h"
#implementation A
- (NSString *)description
{
return [NSString stringWithString: #"A"];
}
+ (NSString *)action
{
return [NSString stringWithString:#"A::action"];
}
#end
Somewhere else:
A *a = [[A class] performSelector:#selector(action)];
NSLog(#"%#",a);
Output:
2009-11-22 23:32:41.974 abc[3200] A::action
nice explanation from http://www.cocoabuilder.com/archive/cocoa/197631-how-do-classes-respond-to-performselector.html:
"In Objective-C, a class object gets all the instance methods of the
root class for its hierarchy. This means that every class object
that descends from NSObject gets all of NSObject's instance methods -
including performSelector:."
In Objective-C, classes are objects as well. The class objects are treated differently, however, as they can call the instance methods of their root class (NSObject or NSProxy in Cocoa).
So it's possible to use all the instance methods defined in NSObject on class objects as well and the right way to dynamically invoke a class method is:
[aClass performSelector:#selector(aSelector)];
The apple docs are a bit more specific.
You shouldn't implement this yourself.
The NSObject Protocol has a performSelector: method that does exactly this.
Is this built-in method what you want?
id objc_msgSend(id theReceiver, SEL theSelector, ...)
(See the runtime reference docs for this function.)

Handling class methods when sub-classing in objective-c

While attempting my first sub-class in Objective-C I have come across the following warning which I cannot seem to resolve. The call to decimalNumberWithMantissa gives a warning of "initialization from distinct Objective-C type".
#import <Foundation/Foundation.h>
#interface NSDecimalNumberSub : NSDecimalNumber {
}
#end
#implementation NSDecimalNumberSub
#end
int main (int argc, char *argv[]) {
NSDecimalNumberSub *ten = [NSDecimalNumberSub
decimalNumberWithMantissa:10
exponent:0
isNegative:NO];
}
Does a class method have to be treated differently with a sub-class? Am I missing something simple? Any help would be appreciated.
NSDecimalNumber defines the decimalNumberWithMantissa:... method to return an NSDecimalNumber, so you're going to get back an instance of the base class and not your custom subclass. You'll have to create your own convenience method to return an instance of your subclass, or just alloc and initialize it another way.
If you're writing your own class you can define a convenience method like that to return type id, and then use [[self alloc] init] when creating the instance to make your class safe for subclassing.