Why need use [self class] when invoking your own class methods? - objective-c

I read a topic at here
http://www.mikeash.com/pyblog/friday-qa-2010-05-14-what-every-apple-programmer-should-know.html. Mike said that "Always use [self class] when invoking your own class methods". But I don't understand why. Can you give an example ?

Lets say that you have class foo, which have the following methods:
+(NSString*) bar{ return #"bar"; }
-(NSString*) barMethod{ return [[self class] bar]; }
Now lets say that you have a class foo2 which inherits from foo. If you override
+(NSString*) bar { return #"bar2" }
the method barMethod will return bar2, as you probably intended for it to.

Unlike other OO languages, class methods in Objective-C are both inherited and can be overridden.
Thus, if you have:
#immplementation Abstract // : NSObject
- (void) doSomethingClassy
{
[Abstract classyThing];
}
+ (void) classyThing
{
... some classy code ...;
}
#end
#interface Concrete : Abstract
#end
#implementation Concrete
+ (void) classyThing
{
... some classy code ...;
[super classThing];
}
#end
Then this won't call Concrete's +classyThing from Abstract's implementation of doSomethingClassy:
[[[Concrete alloc] init] doSomethingClassy];
Whereas if you modify doSomethingClassy to do [[self class] classyThing]; it'll work as expected.
(note that this is a concrete example of Liye Zhang's answer -- feel free to mark his correct as he was first, just not with quite as concrete of an example)

Related

calling Objective-C super class implementation without overridden methods

it seem like when messaging a super class from a subclass that has overridden some methods, you can't get the "original" implementation by just using super. any work arounds or should i init that super class?
here some code showing what i mean:
#interface ClassA : NSObject
- (void)method1;
#end
#implementation ClassA
- (void)method1
{
[self method2];
}
- (void)method2
{
NSLog(#"Hello it's ClassA");
}
#end
#interface ClassB : ClassA
- (void)method3;
#end
#implementation ClassB
- (void)method2 // overriding method2
{
NSLog(#"Hello it's ClassB");
}
- (void)method3
{
[self method1]; // logs "Hello it's Class B" as expected
[super method1]; // still logs "Hello it's ClassB" instead of "Hello it's ClassAā€¯!?
}
#end
thanks in advance for any help :)
It is behaving as expected; you've instantiated an instance of ClassB and, this, when method1 calls [self method2], the method dispatch follows the normal lookup path. self is an instance of ClassB.
Copy/paste this into all your methods:
NSLog(#"%s %p %#", __PRETTY_FUNCTION__, self, self);
That should make it clear what is going on.
any work arounds?
Yes, don't do this as it is poor design. A superclass second guessing inheritance is a sure fire way to end up with an unmaintainable mess of a code base.

Calling Super Class's method from sub class objective C

I have a superclass and subclasses in the following format:
ParentClass.h
#interface ParentClass : NSObject
-(ParentClass *)field:(NSArray *)fields;
#end
ParentClass.m
#import "ParentClass.h"
#implementation ParentClass
-(id)init{
self = [super init];
if (self == nil) {
return self;
}
return self;
}
-(ParentClass *)field:(NSArray *)fields{
ParentClass *pc = [[ParentClass alloc] init];
// code
return pc;
}
#end
Subclass.h
#interface Subclass : ParentClass
-(Subclass *)field:(NSArray *)fields;
#end
Subclass.m
#import "Subclass.h"
#implementation Subclass
-(id)init{
self = [super init];
if (self == nil) {
return self;
}
return self;
}
-(Subclass *)field:(NSArray *)fields{
// code
return (Subclass *)[self field:fields];
}
#end
I guess the issue is here.
return (Subclass *)[self field:fields];
I'm not accessing the parent class method the way I should. Can anyone tell what should be the right way instead?
What if i call this way?
-(Subclass *)subClassField:(NSArray *)fields{
return (Subclass *)[self field:fields];
}
and i replaced the
-(Subclass *)field:(NSArray *)fields;
with
-(Subclass *)subClassField:(NSArray *)fields;
First please note that this code
-(ParentClass *)field:(NSArray *)fields{
ParentClass *pc = [[ParentClass alloc] init];
// code
return pc;
}
Doesn't look right from the software design perspective. From what you posted it seems that ParentClass instances can create and return other instances of its own type from the field method. This doesn't look ok, but it could be fine depending on what your intentions are.
Consider making ParentClass and FieldClass different classes if that makes sense.
Regarding the subclass, the way of doing what you want would be this:
-(ParentClass *)field:(NSArray *)fields
{
// code
return [super field:fields];
}
Note that I changed the returned type to be (ParentClass *), and the self to super. You cannot return a ParentClass object in the place of a SubClass object (the latter could have extra data that former doesn't know about). Doing the opposite is valid (you can return a Subclass object when someone expects to receive an object of ParentClass type).
Having said that is pretty unclear what you're trying to achieve, I'll tell what's wrong. First of all isn't enough to cast a pointer to a base class pointer, to call the superclass method, you should call it this way:
return (Subclass*) [super field:fields]; // Still wrong
But you're break polymorphism, and as the method signature says, you're returning a Subclass object, and the user that calls this method expects to have a Subclass object, but at the first call of a method that is just implemented by the subclass, it crashes because you're returning an instance of the superclass. Maybe is enough for you to change the method signature to return a ParentClass pointer, but this makes the method useless, why overriding it? It isn't pretty clear what you're trying to do, and what's your logic path.
Edit
Having seen the code that you posted on Github, here the situation is pretty different. In the Java code,t he method field returns this, so no new object gets created, and the method is just used for side effects. The add method doesn't break polymorphism, because just the object reference is of the parent class type, but if executed on a subclass it returns the object itself (this), which is of the subclass type.
In Objective-C for these cases the id type is used, which is used to represent a whatever object pointer, to a whatever class. You could also use the ParentClass type, but I'll stick to conventions. Here's an indicative code:
#implementation ParentClass
#synthesize endpoint
- (id) add: (NSString*) endpoint fields: (NSArray*) fields
{
<code>
return self;
}
- (id) field: (NSArray*) fields
{
return [self add: self.endpoint fields: fields];
}
#end
#implementation SubClass
- (id) field: (NSArray*) fields
{
< Additional code >
return [self add: self.endpoint fields: fields];
}
#end

Objective-C if ([self isKindOfClass: ... ]) static method

I seek help in understanding why code behaves so strange. What I have: BaseClass : NSManagedObject and ChildClass : BaseClass
BaseClass has a category. .h:
#interface BaseClass (Category)
+ (NSArray)method;
#end
.m:
#implementation BaseClass (Category)
+ (NSArray *)method
{
if ([self isKindOfClass:[ChildClass class]) {
do stuff
return resultArray;
}
return nil;
}
From another place in project I call *array = [ChildClass method];. In the BaseClass (Category) implementation console reads self = (Class)ChildClass, but still the execution flow skips the if and passes right to return nil; for some reason, that is beyond my understanding. Any suggestions why that may be? All answers are appreciated. Thanks.
... as I don't have enough rep points, I'm not posting the screenshots. Hope I was clear.
You're in a static method, so self represents the class itself. Is enough to do this:
if (self==[ChildClass class]) {
do stuff
return resultArray;
}
You might be better off doing [[childOrBaseInstance class] method]; in your code that is calling +method.
ChildClass would have it's own +method that override's BaseClass's +method.
Any time you check your class and do something different, ask yourself if you're just manually recreating polymorphism.

Objective-C and component programming

I am trying to implement the concept of component programming while writing my iOS game.
In the book "Component Software: Beyond Object-Oriented Programming" by Clemens Szyperski, he mentions a tactic:
(not quote)
Start with a Duck class, which adds component Quack.
Class Quack implements an interface on whichever object that calls it, the interface specifies a method which uses Quacks quack()
With this setup, Duck has no reference or awareness about Quack except for when it's instantiated, and is never used in Duck thereafter. Other objects can call duckObject.quack() and reach Quack while only being aware of Duck object.
So far, I've been trying to implement this without success. Preferably, Duck should need no more code than instantiation, the rest placed in Quack class. Can this be done in Objective-C (for iOS?), or am I better off leaving COP for other languages?
I don't think there's an exact comparison in ObjC, but it sounds like you want to look into message forwarding. If an object is sent a message to which it doesn't respond, right before an error is signaled, the runtime sends the object forwardInvocation:, with an NSInvocation argument that encapsulates the message and arguments.
In forwardInvocation:, an object can pass along the invocation to another object which does handle that message. This allows a Duck instance to respond to the message quack, even though quack is not implemented by Duck, by holding a reference to an instance of Quack, which does implement it:
- (void)forwardInvocation:(NSInvocation *)anInvocation
{
if( [myQuack respondsToSelector:[anInvocation selector]] ){
[anInvocation invokeWithTarget:someOtherObject];
}
else{
[super forwardInvocation:anInvocation];
}
}
Not really sure what your question is. It sounds like you want a weak reference to a class.
First the duck class
//Duck.h
#import "Quack.h"
#interface Duck : NSObject {
Quack *quacker;
}
#property (nonatomic, retain) Quack *quacker;
#end
//Duck.m
#implementation Duck
#synthesize quarker;
-(id) init {
self = [super init];
if(self) {
}
return self;
}
-(Quack *)quacker {
if(quacker == nil) {
[self setQuacker:[[[Quack alloc] init] autorelease]];
}
return quacker;
}
#end
Then implement the Quack class.
//Quack.h
#interface Quack : NSObject {
}
-(void)quack;
#end
//Quack.m
#implementation Quack
-(id) init {
self = [super init];
if(self) {
}
return self;
}
-(void)quack {
NSLog(#"quack");
}
#end
Now in what ever class you want:
//RandomClass.m
[[[self duck] quacker] quack];

Method signature for a Selector

I'm new to the Objective C business (Java developer most of the time) and am woking on my first killer app now. :-)
At the moment I am somehow confused about the usage of selectors as method arguments. They seem to be a little bit different than delegates in C# for example.
Given the following method signature
-(void)execute:(SEL)callback;
is there a way to enforce the signature for the selector passed to such a method?
The method is expecting a selector of a method with the following signature
-(void)foo:(NSData*)data;
But the SEL (type) is generic, so there is a good chance to pass a wrong selector to the
execute method. OK at least at runtime one would see a funny behavior... but I would like to see a compiler warning/error when this happens.
The quick answer is: no, there is no way to have the compiler enforce the method signature of a method selector that is provided via a SEL argument.
One of the strengths of Objective-C is that it is weakly-typed language, which allows for a lot more dynamic behaviour. Of course, this comes at the cost of compile-time type safety.
In order to do what (I think) you want, the best approach is to use delegates. Cocoa uses delegates to allow another class to implement "callback"-type methods. Here is how it might look:
FooController.h
#protocol FooControllerDelegate
#required:
- (void)handleData:(NSData *)data forFoo:(FooController *)foo;
#end
#interface FooController : NSObject
{
id <FooControllerDelegate> * delegate;
}
#property (assign) id <FooControllerDelegate> * delegate;
- (void)doStuff;
#end
FooController.m
#interface FooController (delegateCalls)
- (void)handleData:(NSData *)data;
#end
#implementation FooController
#synthesize delegate;
- (id)init
{
if ((self = [super init]) == nil) { return nil; }
delegate = nil;
...
return self;
}
- (void)doStuff
{
...
[self handleData:data];
}
- (void)handleData:(NSData *)data
{
if (delegate != nil)
{
[delegate handleData:data forFoo:self];
}
else
{
return;
// or throw an error
// or handle it yourself
}
}
#end
Using the #required keyword in your delegate protocol will prevent you from assigning a delegate to a FooController that does not implement the method exactly as described in the protocol. Attempting to provide a delegate that does not match the #required protocol method will result in a compiler error.
Here is how you would create a delegate class to work with the above code:
#interface MyFooHandler <FooControllerDelegate> : NSObject
{
}
- (void)handleData:(NSData *)data forFoo:(FooController *)foo;
#end
#implementation MyFooHandler
- (void)handleData:(NSData *)data forFoo:(FooController *)foo
{
// do something here
}
#end
And here is how you would use everything:
FooController * foo = [[FooController alloc] init];
MyFooHandler * fooHandler = [[MyFooHandler alloc] init];
...
[foo setDelegate:fooHandler]; // this would cause a compiler error if fooHandler
// did not implement the protocol properly
...
[foo doStuff]; // this will call the delegate method on fooHandler
...
[fooHandler release];
[foo release];
To directly answer your question, no, the SEL type allows any type of selector, not just ones with a specific signature.
You may want to consider passing an object instead of a SEL, and document that the passed object should respond to a particular message. For example:
- (void)execute:(id)object
{
// Do the execute stuff, then...
if ([object respondsToSelector:#selector(notifyOnExecute:)]) {
[object notifyOnExecute:self];
}
// You could handle the "else" case here, if desired
}
If you want to enforce the data handling, use isKindOfClass inside your selector. This works a lot like instanceof which you are familiar with in Java.