In class method, difference between [self someMethod] and [[self class] someMethod] - objective-c

The context is in a class (ie +) method, in a (apparently bug-free) method in the superclass implementation of the actual class --
I see
something = [self someMethod];
and
something = [[self class] someMethod];
In both cases someMethod has an implementation in the "actual" subclass (as well as in the current superclass), and the subclass implementation is what is expected to be invoked.
Is there any practical difference between the two forms, or some reason to prefer one over the other?

the difference is that you can safely copy and paste the method anywhere whit [self class].
I don't think that there is some other difference.

There's no practical difference, because +class returns the class object, which is exactly what self points to in a class method. In other words,
+ (BOOL)selfEqualsClassObject {
return self == [self class];
}
will always return YES.
Given that, I can't see any reason to prefer sending an extra message. I would say just use self.

Related

How Class Method can access Instance Method ?

I am from Actionscript Background. In Actionscript Class Method can access only Class Methods and Class properties.
But In Objective C,
How Class method gameResultAll can access Instance Method initFromPlist
+(NSMutableArray *)gameResultAll://Class Method
-(id)initFromPlist:(id)plist;//Instance Method
NSMutableArray *gameResults = [GameResult gameResultAll]; // (returns GameResult array)
Why [self init] method is called instead of [super init] to create an instance from class method.
Thanks in advance.
#import "GameResult.h"
#implementation GameResult
#define GAME_RESULT_KEY #"gameresult_key"
#define SCORE_KEY #"score"
+(NSMutableArray *)gameResultAll
{
NSMutableArray *resultArray = [[NSMutableArray alloc] init];
for (id plist in [[[[NSUserDefaults standardUserDefaults] dictionaryForKey:GAME_RESULT_KEY] mutableCopy] allValues])
{
GameResult *gameResult = [[GameResult alloc] initFromPlist:plist];
[resultArray addObject:gameResult];
}
return resultArray;
}
//Designated initialiser
-(id)initFromPlist:(id)plist
{
self = [self init];
if(self)
{
if([plist isKindOfClass:[NSDictionary class]])
{
NSDictionary *resultDictionary = (NSDictionary*)plist;
_score = (int)resultDictionary[SCORE_KEY];
}
}
return self;
}
You asked:
How Class method gameResultAll can access Instance Method initFromPlist
It can access that method because you used the alloc method, which creates an instance of GameResult. Now that you have an instance, you can use instance methods in conjunction with this instance.
By the way, this is a very common pattern, a "convenience" class method that allocates an instance of an object (with alloc) and initializes the object (with init or some permutation of that). Or, as in this case, it can create an array of these objects.
You then go on to ask:
Why [self init] method is called instead of [super init] to create an instance from class method.
I can understand the confusion, but there is an important, yet subtle distinction in the behavior of these two.
Imagine this scenario:
At some future date, you subclass GameResult, e.g. ArcadeGameResult;
You implemented an init method for ArcadeGameResult that initializes some properties unique to this subclass; and
You happen to initialize a ArcadeGameResult instance like so:
ArcadeGameResult *agr = [[ArcadeGameResult alloc] initFromPlist:plist];
Because the initFromPlist uses [self init], it means that the the initFromPlist method of GameResult will end up calling the init method of the object (which in this example, is actually a ArcadeGameResult object). But if initFromPlist in GameResult called [super init] instead, it would not have called ArcadeGameResult's init method and thus initFromPlist would be problematic if ever used in conjunction with a subclass.
Bottom line, unless the method you're calling is the exact same method signature, it's safer to call the self rendition rather than the super rendition. It's a little more flexible in case you ever decide to subclass in the future.
There is a corollary to the counsel. When calling class methods from an instance method, you should refer to [self class] rather than the class name. So, imagine your GameResult class had a class method:
+ (void)someClassMethod
{
// do something
}
If you had some GameResult instance method that was going to avail itself of this method, you might be tempted to write:
- (void)someInstanceMethod
{
// do some stuff
[GameResult someClassMethod];
}
But that's not a good idea. You would instead use the following:
- (void)someInstanceMethod
{
// do some stuff
[[self class] someClassMethod];
}
They look very similar, but the latter lets you implement a someClassMethod in a subclass, and this instance method will still work. If you use the former construct, the subclassed class method wouldn't be called by someInstanceMethod.
These are subtle issues, and probably not critical for your current code sample. But hopefully it illuminates the choice of [self init] versus [super init] in this situation.
In Actionscript Class Method can access only Class Methods and Class properties.
That's not different in Objective-C either (because nothing else would make sense), so:
How Class method GameResultAll can access Instance Method initFromPlist
Only through a valid instance.
Why [self init] method is called instead of [self super] to create an instance from class method.
Because the latter is a syntax error, perhaps? Read a basic Objective-C tutorial.

Find the Selector of a Class method

I'm quite a newbie in Objective C, though I have some background in Java reflection.
Here, I have a classic class method findAll that find all the domain objects from the database. The class Univers directly inherits from DomainObject
#interface DomainObject : NSObject
- (NSString *) execute : (NSString*) method withJson:(NSString*)json;
+ (NSString*)findAll: (NSString*)json;
#end
#implementation DomainObject
- (NSString *) execute: (NSString*) method withJson:(NSString*)json{
method = [NSString stringWithFormat:#"%#%#", method, #":"];
//method is 'findAll:'
NSString* result = [ self performSelector:
NSSelectorFromString(method) withObject:json];// Error here
return result;
}
#end
The code was working when findAll was NOT a class method (ie -findAll declaration), but now I have the error : NSInvalidArgumentException -[Univers findAll:]
It clearly seems that the runtime is looking for an instance method.
Any idea to find my class method ?
Instead of calling
NSString* result = [self performSelector:NSSelectorFromString(method) withObject:json];
you need to call
NSString* result = [[self class] performSelector:NSSelectorFromString(method) withObject:json];
for class methods.
After all it's the object instance's class that supposed to be calling the method, not the instance itself.
Short explanation: NSObject implements - (Class)class; (not to be mistaken with + (Class)class of similar effect, which NSObject implements, too!) which returns the Class object of your instance object. Keep in mind that in Objective-C in addition to plain instance objects, Classes are actual objects, too: objects of type Class, that is (vs. id, NSObject, …).
See the documentation for the -class method here.
Btw, you should probably wrap your method call into an conditional block to prevent exceptions caused by calls to missing methods.
SEL selector = NSSelectorFromString(method);
if ([[self class] respondsToSelector:selector]) {
NSString* result = [[self class] performSelector:selector withObject:json];
}
In general it's a common pattern in Objective-C to call an object's class method by receiving the class object via [object class].
Consider this case of a class called Foo implementing a convenience method for returning an autporeleased instance of itself (to be called via: Foo *newFoo = [Foo foo];):
While it would certainly be possible to implement said method like this (after all we know the object's class name, right?):
+ (id)foo {
return [[[Foo alloc] init] autorelease];
}
the correct way is this:
+ (id)foo {
return [[[self alloc] init] autorelease];
}
As the first one would cause problems with polymorphism in subclasses (Such as a subclass called FooBar, for which it should clearly be [FooBar alloc] …, not [Foo alloc] …. Luckily [[self class] alloc] solves this dynamically).
While this is clearly not the right place for a thorough explanation of this (rather offtopic one might say) it's certainly worth noting/warning about, imho.

What's the Point of Using [self class]

Is this code correct
#implementation Vehicle
+(id) vehicleWithColor:(NSColor*)color {
id newInstance = [[[self class] alloc] init]; // PERFECT, the class is // dynamically identified
[newInstance setColor:color];
return [newInstance autorelease];
}
#end
Why use [self class]
I thought self already points to the class on static methods (the ones with +)
You're right: [self class] is unnecessary in a class method (it's more commonly called that in Objective-C rather than "static" method), because self is already a class, and [self class] returns itself.
But it gets a bit more interesting. In Objective-C, class objects are technically instances of metaclasses. So [self class] in a class method ought to return the metaclass instead of the class itself. But for practical purposes, Objective-C hides the metaclass so it handles this case specially.
Some good reading on this topic:
http://www.sealiesoftware.com/blog/archive/2009/04/14/objc_explain_Classes_and_metaclasses.html
Inheritance diagram: http://www.sealiesoftware.com/blog/class%20diagram.pdf
http://cocoawithlove.com/2010/01/what-is-meta-class-in-objective-c.html
It's to support subclassing. If you hard-coded the class name, as in [[Vehicle alloc] init], then a subclass of Vehicle would have to override +vehicleWithColor: to make it do the right thing. With [self class], you could create a subclass HarleyDavidson, and [HarleyDavidson vehicleWithColor:[NSColor blackColor]] would do the right thing automatically, creating an instance of HarleyDavidson instead of an instance of Vehicle.
(Edit:)
See Joe's comment below concerning self vs. [self class] in class methods - In class methods, it doesn't make a difference. But there is a situation where it can. Classes can respond to instance methods that are defined in a root class - -class itself is just such a method, defined as an instance method in the NSObject protocol. So if you extend a root class such as (for example) NSObject by adding an instance method, that method should always use [self class] if it needs to refer to its own Class object.

How to call a method of super.super?

I want to call a method of super class of a super class, without breaking the inheritance chain. Something like this:
+(id) alloc
{
return [super.super alloc];
}
Is there a way to achieve this ?
Do not confuse with behavior offering by superclass method, discussed here.
UPD:
A few words about super and superclass differences.
Lets say, we have AClass and SuperAClass. As follows from their names AClass inherits SuperAClass. Each of them has an implementation of a method -(void) foo;
AClass implements one of the following class methods:
1. superclass:
+(id) alloc {
return [[self superclass] alloc];
}
2. super:
+(id) alloc {
return [super alloc];
}
Now, suppose these 2 lines of code:
AClass *AClassInstance = [AClass alloc];
[AClassInstance foo];
In first case (using superclass), SuperAClass's foo method will be called.
For the second case (using super), AClass's foo method will be called.
In your particular example, +superclass is actually the way to go:
+ (id)someClassMethod {
return [[[self superclass] superclass] someClassMethod];
}
since it is a class method, hence self refers to the class object where +someClassMethod is being defined.
On the other hand, things get a tad more complicated in instance methods. One solution is to get a pointer to the method implementation in the supersuper (grandparent) class. For instance:
- (id)someInstanceMethod {
Class granny = [[self superclass] superclass];
IMP grannyImp = class_getMethodImplementation(granny, _cmd);
return grannyImp(self, _cmd);
}
Similarly to the class method example, +superclass is sent twice to obtain the supersuperclass. IMP is a pointer to a method, and we obtain an IMP to the method whose name is the same as the current one (-someInstaceMethod) but pointing to the implementation in the supersuperclass, and then call it. Note that you’d need to tweak this in case there are method arguments and return values different from id.
Thanks to Bavarious who inspired me to involve some runtime staff.
Briefly, the desired hypothetical line:
return [super.super alloc];
can be transformed in this "real" one:
return method_getImplementation(class_getClassMethod([[self superclass] superclass], _cmd))([self class], _cmd);
To make it relatively more clear, it can be expanded as follow:
Method grannyMethod = class_getClassMethod([[self superclass] superclass], _cmd);
IMP grannyImp = method_getImplementation(grannyMethod);
return grannyImp([self class], _cmd);

Why should I call self=[super init]

Let's say I create my class and its init method. Why should I call and return value of superclass init assigned to self? Which cases it covers?
I would appreciate examples why would I need it for Cocoa superclass and non-Cocoa.
You mean why
self = [super init];
rather than
[super init];
Two reasons:
in initialisation, failure is indicated by returning nil. You need to know if initialisation of the super object failed.
the super class might choose to replace the self returned by +alloc with a different object. This is rare but happens most frequently with class clusters.
Edited in response to Michael's comment:
I can understand why I need to save and return [super init]. But is it just convention and good looking makes us use self as a temporary variable to pass result along?
No. Instance variables are accessed relative to the self pointer, so in the following:
-(id) init
{
self = [super init];
if (self != nil)
{
myBoolIvar = YES;
// The above is an implicit version of self->myBoolIvar = YES;
}
return self;
}
self has clearly got to point to the right block of memory i.e. the one you are going to return.
The other point is that if super init returns different class instance then the rest of the code after that line may not even make sense, lead to memory leaks and crashes, not even talking about the object instantiated from that class.
That could be a problem. If I subclassed NSNumber and [super init] decided to return an NSString (which it could - there's nothing to stop it) that would clearly be a disaster. Whatever super returns from -init must be "compatible" with the subclass in the sense of providing space for ivars and being further subclassible or it's a horrendous bug (unless, of course, the problem is documented). So, in general, you don't need to worry about checking the class. However, do read the documentation. See for instance the section on subclassing NSString in NSString's docs.
I know it is a little bit late for my answer, but I cannot stop myself from posting a link which I found very useful in clearing my doubt about this problem.
Matt Gallagher: What does it mean when you assign [super init] to self?
EDIT: As per the comments, here are the essential points in the link
To understand why self=[super init]; we need to consider many points. Let's tackle it one by one.
What is self
Every method has two hidden parameters: self and _cmd. So the method call
- (id)initWithString:(NSString *)aString
is changed by compiler into a function call like this
id initWithString(id self, SEL _cmd, NSString *aString);
Why do we need self?
The reality is that the compiler uses the self parameter to resolve any reference to an instance variable inside a method.
Suppose that we have a method setValueToZero and value is an instance variable of the class it belongs to, then the implementation
- (void)setValueToZero
{
value = 0;
}
will be converted by the compiler into a function like this
void setValueToZero(id self, SEL _cmd)
{
self->value = 0;
}
Do self already have a value when init is called?
Following is an example of a typical object creation and initialization.
[[MyClass alloc] initWithString:#"someString"]
Here, by the time we get into the initWithString method, self will have the newly allocated object as its value (i.e., the return value from [MyClass alloc]). In fact, it is almost guaranteed to be the correct, final value.
Why self = [super init];?
It is because [super init] is permitted to do one of the three things:
Return its own receiver (the self pointer doesn't change) with inherited instance values initialized.
Return a different object with inherited instance values initialized.
Return nil, indicating failure.
In the first case, assignment has no effect on self. In the third case, the initialization has failed, self is set to nil and it is returned.
The reason behind assignment to self is with the second case. Consider the following
- (id)initWithString:(NSString *)aString
{
self = [super init];
if (self)
{
instanceString = [aString retain];
}
return self;
}
We want the conversion from
instanceString = [aString retain];
to
self->instanceString = [aString retain];
to act on the correct value and thus we have to change the value of self.
When would [super init] return a different object?
In one of the following situations
Singleton object (always returns the singleton instead of any subsequent allocation)
Other unique objects ([NSNumber numberWithInteger:0] always returns the global "zero" object)
Class clusters substitute private subclasses when you initialize an instance of the superclass.
Classes which choose to reallocate the same (or compatible) class based on parameters passed into the initializer.
In all but the final case, continuing to initialize the returned object if it changes is a mistake — the returned object is already completely initialized and isn't necessary related to your class anymore. So a better init approach will be as follows
- (id)initWithString:(NSString *)aString
{
id result = [super init];
if (self == result)
{
instanceString = [aString retain];
}
return result;
}
Conclusion
You don't need to assign [super init] to self to make most classes work. In some obscure cases, it is actually the wrong thing to do.
So why do we continue to assign to self? It's the traditional template for an initializer, and although it's wrong in some cases, it is right in other cases which have been written to expect this approach.
Basically every Objective-C class is a subclass. It's either some class you've specified or NSObject.
In the subclass (your class that you're working on) you call
self = [super init]
What this basically does is calls the super class's (the ones I mentioned above) init method (the constructor) and assigns it to the current class.
This makes sure that the superclasses' initializing method is called.
Now for
If(self)
This basically checks if the above piece of code worked.
This is done to insure that if you call some Instance Variable of the super class, you'll be able to do so.
In most cases, setting self to [super init] does nothing since [super init] will wind up returning self anyway. There are some rare cases, however, where [super init] will return something different. It may return nil if it fails to initialize the superclass for some reason or it may decide to return a completely different object.
Source
Implementing The Designated Initializer
**
self
**
Inside a method, self is an implicit local variable. There is no need to declare it, and it is automatically set to point to the object that was sent the message. (Something like this in Android programming.) Typically, self is used that an object can send a message to itself. Example here:
return self;
**
super
**
When we overriding a method, we want to keep what method of the superclass is doing and have your subclass add something new on that. To make it easier, there is compiler directive in Objective-C called super.
How does super work? Usually when you send a message to an object, the search for a method of that name starts in the object's class. If there is no such method, the search continues in the superclass of the object. The search will continue up the inheritance hierarchy until a suitable method is found. (If it gets to the top of the hierarchy and no method is found, an exception is thrown).
When we send a message to super, we are sending message to self, but the search for the method skips the object's class and start at the superclass. In the above case, we send init message to super. This calls NSObject's init method.
Because you have to initialize the object somehow, and presumably you want to do any initialization a superclass required be done, since you're descending from it.