super bound statically at compile time? - objective-c

I want to create a class cluster with a base class and 2 subclasses. Creating an instance of the base class should return a subclass based on some conditions, but creating a subclass directly should create it. I wrote the following code in the base class:
+ (id)allocWithZone:(NSZone *)zone {
// prevent infinite recursion
if ([self isEqual:Base.class]) {
// if self is the base class, return a correct subclass
if (somecondition) {
return [SubclassA alloc];
}
return [SubclassB alloc];
}
// otherwise, alloc is called on a subclass
// call NSObject's alloc
return [super allocWithZone:zone];
}
and it works, but I'm really surprised that it does. Namely, when invoked on a subclass, why does super evaluate to the Base class's superclass (NSObject), and not the Base class (because invoked on SubclassA, the superclass is Base)? It is as if the allocWithZone: method call, inherited from Base, just always evaluated super relative to Base, not the real runtime class of the caller. I think similar code in Java and other OO languages would not work and result in infinite recursion, would it? Is this code wrong?

Your code is correct. [super ...] always uses the superclass of the class implementing the method. In your code, +allocWithZone: is implemented by class Base, so [super allocWithZone:zone] uses Base's superclass when searching for the next +allocWithZone: implementation to call.

Related

self concept ,if i use self in class method not in instance method

#interface hello:SKScene
#end
#implementation hello
+(void)method{
[self here];
}
#end
main.m
[hello method];
here,when i call this class method without allocating memory for object then method self,belong to whom????
my question is self belong to class that contain the method calling on then because i did not define object then ,why i still can use self on this?????
is it still belong to class on which it calling ??please give me proper concept of self on instance method and class method.
When you refer to self in class method, self refers to the class, itself, not to a particular instance of that class. By using self rather than the actual class name in these class methods, it makes it easier to subclass the class in question. Specifically, the class method will be inherited, but the self references will now refer to the subclass rather than the base class. If you refered to the base class by name, this would not be true.
Consider this factory method:
#implementation BaseClassObject
// THIS IS WRONG
+ (BaseClassObject *)object {
return [[BaseClassObject alloc] init];
}
#end
And consider this subclass:
#interface SubClassObject : BaseClassObject
#end
Then consider code that does:
SubClassObject *object = [SubClassObject object]; // WRONG
The problem is that the object factory method will return a BaseClassObject rather than a SubClassObject. But that is remedied if we alter the definition of that factory class method to use self:
#implementation BaseClassObject
// THIS IS RIGHT
+ (instancetype)object {
return [[self alloc] init];
}
#end
Now when I refer to [SubClassObject object], I'll get an instance of SubClassObject rather than BaseClassObject.
Note: In my contrived example, it's rather important to use self. You may, though, encounter code where it does not appear to be immediately relevant (for example, you might have a base class, but no subclass at this time).
Even in this case, you probably should be in the habit of using self in these class methods, regardless, to "future-proof" your code, so that if you ever subclass this base class at some unforeseen date in the future, these class methods are more likely to function properly even when subclassed.
Just to add a little to Rob's answer: the class object is created automatically by the compiler and/or Objective-C runtime. (It doesn't matter to you which it is.) For all intents and purposes, it's permanent. There's no need for it to be managed.

Call Superclass method

In Objective-C, how do I call an object's super class method?
For example, lets say I have an instance of an object "foo".
"foo" has a method that is overriden. I do not want to call this overriden method. Instead, I want to call the original method on the foo object instance.
You cannot do:
[[instance super] super_method]; as far as I am aware. So how can I go about doing this?
I know I can add a method to foo:
-(void) callsuper
{
[super super_method];
}
and do:
[foo callsuper];
Any other ways? I really don't want to create a method just to do that.
The keyword super does this for you. It is seen very commonly in -init methods. Here is an example.
- (id)init {
if (self = [super init]) {
// custom initialization
}
return self;
}
In this case, the super keyword is used to call this class' superclass implementation of the -init method. super can be used on any method that your superclass implements.

Prevent ObjC "abstract" class' init method from being called while allowing [super init]?

Say I have a pseudo-abstract base class that users should not instantiate. Basically I want to throw a warning when they're trying to call init on the class, or return one of the concrete instances with default values.
However, the concrete implementations of that base class have to call [super init] in their initializers. That should of course be allowed.
How would I best go about this?
I was thinking that this should be fine:
#implementation KTPhysicsShape
-(id) init
{
// throw exception here or return concrete instance with default values
}
// this is what subclasses would call in place of [super init]:
-(id) internal_initFromSubclass
{
return [super init];
}
#end
Any concerns about this approach? I know others could still call the internal method, but I'm mostly concerned about disallowing init since that's what users would try to call foremost.
I have also worked at the problem of how to have effectively abstract classes, but I'm not that into this solution. It seems to me that it's going to make your subclass code look weird and harder to read for casual observers.
If you require that your subclasses do particular initialization in -init, yours may the only solution. But if you just want to ensure that they have subclassed, you can do that within -init:
-(id) init
{
NSAssert(![self isMemberOfClass:[KTPhysicsShape class]],
#"KTPhysicsShape must be subclassed!");
return [super init];
}
This indicates that your architecture has a serious flaw. The whole point of the designated initializer chain is that it can be executed in a predictable order without variation. Adding contractual obligations to the subclasses to not follow the normal chain adds fragility and unneeded complexity.
The crux of the flaw is that you have an abstract class that doesn't appear to be truly abstract; it can have concrete instances and that requires concrete initialization.
First, why can't you break the class into a truly abstract class and a concrete class?
If you can't (or don't want to -- certainly, more classes has costs of its own), then one solution is to break out the commonly used initialization operations into a separate method:
- (void) commonKTPhysicsShapeInit
{
....
}
That does not call super. This would not be declared in your header; it is an internal-to-implementation-only method, thus the name.
Then, let your subclasses call through the standard designated initializer that calls commonInit. For concrete instances of that class, have a separate initializer that both calls commonInit and does the concrete initialization dance.
It is similar to what you proposed, but presents the interface in a fashion that follows existing patterns more closely.

Objective-C Simple Inheritance and OO Principles

I have a subclass SubClass that inherits from baseclass BaseClass.
BaseClass has an initializer, like so:
-(id)init {
self = [super init];
if(self) {
[self commonInit];
}
return self;
}
-(void)commonInit {
self.goodStuff = [[NSMutableArray alloc]init];
}
SubClass does its initializer, like so:
-(id)init {
self = [super init];
if(self) {
[self commonInit];
}
return self;
}
-(void)commonInit {
self.extraGoodStuff = [[NSMutableArray alloc]init];
}
Now, I've *never taken a proper Objective-C course, but I'm a programmer more from the Electrical Engineering side, so I make do. I've developed server-side applications mostly in Java though, so I may be seeing the OO world through Java principles.
When SubClass is initialized, it calls the BaseClass init and my expectation would be — because inheritance to me implies that characteristics of a BaseClass pass through to SubClass — that the commonInit method in BaseClass would be called during BaseClass init.
It is not. I can *sorta understand maybe-possibly-stretch-my-imagination why it wouldn't be. But, then — why wouldn't it be based on the principles of OOP? What does "self" represent if not the instance of the class of the running code?
Okay, so — I'm not going to argue that what a well-developed edition of Objective-C is doing is wrong. So, then — what is the pattern I should be using in this case? I want SubClass to have two main bits — the goodStuff that BaseClass has as well as the extraGoodStuff that it deserves as well.
Clearly, I've been using the wrong pattern in this type of situation. Am I meant to expose commonInit (which makes me wonder about encapsulation principles — why expose something that, in the Java world at least, would be considered "protected" and something that should only ever be called once for each instance)?
I've run into a similar problem in the recent past and tried to muddle through it, but now — I'm really wondering if I've got my principles and concepts all straight in my head.
Little help, please.
Let me clarify — I get that self ends up being SubClass when I call init on super. That I can see when I debug, etc.
What's the pattern for overriding methods in this sort of situation? Where I have a bit of common initialization that may get called from several init methods in the super class? Do I have to put the code in every variation of init?
self and super are just a pointers to a memory location, they point to the same address where your object are allocated, but they are treated special by the Objective-C compiler:
super starts overload resolution at the first super type, ie. the parent type (BaseClass in this case).
self starts overload resolution at the current runtime type that the pointer points to. That is why you cannot call BaseClass commonInit from BaseClass, since self points to a SubClass. If you want to do this, you should have the commonInit in SubClass call [super commonInit].
self in BaseClass' constructor in your example is of type SubClass, so [self commonInit] calls SubClass' commonInit override , not BaseClass' commonInit method.

Why to use [super init] in Objective C constructors?

Say I have a class named Item. Which is a superclass of NewsItem and TwitterItem.
If I want to create some NewsItem's do I have to use (inside constructor)
self = [super init];
If yes, why? In Java/C# I would just do,
NewsItem n = new NewsItem();
I don't have to do anything with superclasses in Java/C#. Just can't grasp it.
In Java and C#, the compiler automatically makes your constructor call the superclass constructor if you don't explicitly call it. For example, the “Java Tutorials” say this:
If a constructor does not explicitly invoke a superclass constructor, the Java compiler automatically inserts a call to the no-argument constructor of the superclass. If the super class does not have a no-argument constructor, you will get a compile-time error. Object does have such a constructor, so if Object is the only superclass, there is no problem.
In Objective-C, the compiler doesn't do it automatically, so you have to do it yourself.
Because your superclass (and your superclass's superclass) need a chance to initialize, too.
And, keep in mind, that your superclass will [rarely] return nil or a different instance.
Which is why you do:
- (id)init
{
self = [super init];
if (self) {
... init stuff ....
}
return self;
}
Because you are overriding the init message. If you don't override it then [[NewsItem alloc] init] would just call the superclass' init message. In C#, you might use base to do the same.
since your custom object will at least inherit from the mothers of all Objects: NSObject, you have to call '[super init];'
'super' simply does call the init Method of its superclass