Why override the designated initializer of super class? - objective-c

I was reading the book "Cocoa Design Pattern" and 2 of its point, in chapter 3 (Two-Stage Creation) are making me confused.
Make sure that the superclass’ Designated Initializer is overridden to call the new Designated Initializer.
When subclassing, make sure every new initializer that isn’t the Designated Initializer calls the Designated Initializer.
My question is how we can call the method for which we don't have the parameters to pass? The book example is being posted below. In this method writer has passed some "static" values, but are we supposed to do this? Or is this always desirable?
My second question is, why I have to override the designated method of super class when I will never call it when I will be initializing my object, other than in my own designated initializer, where I will not be passing any parameters (e.g; in case of NSObject)
#interface MYCircle : NSObject {
NSPoint center;
float radius;
}
// Designated Initializer
- (id)initWithCenter:(NSPoint)aPoint radius:(float)aRadius;
#end
#implementation MYCircle
// Designated Initializer
- (id)initWithCenter:(NSPoint)aPoint radius:(float)aRadius {
self = [super init];
if(nil != self) {
center = aPoint;
radius = aRadius;
}
return self;
}
#end
// Overriden inherited Designated Initializer
- (id)init {
static const float MYDefaultRadius = 1.0f;
// call Designated Initializer with default arguments
return [self initWithCenter:NSZeroPoint radius:MYDefaultRadius];
}
Please also help me to correct my question because I am not sure what I am really asking is a correct question.
Thanks.

The designated initializer is the one that properly configures the object. If you don't choose one init... method as the designated initializer, then you have to make sure that every init... method does the right thing. That generally means that they all have to have the same code, or they all have to call a common setup method. It also means that anyone subclassing your class has to override all the init... methods instead of just one.
By picking (i.e. "designating") one init... method as the common method that all the others call, you give subclasses a single override point and a single method that their own init... methods can call to ensure that the superclass is properly configured.
If you don't have the data necessary to call the designated initializer, then you don't have the data required to set up the superclass. Somestimes you can choose reasonable default values, as above, but if not then it doesn't make any sense to create the object at hand.

Related

Beginner Objective-C: Extending a class?

I'm very new with objective-C, and I am trying to implement a 'factory' style class extending a cocos2D class called CCSprite.
I want there to be a class Monster which extends CCSprite that will create and issue sprites with unique IDs so that I may call and manipulate the generated sprites later on; I am extending CCSprite to add an instance_id property and a static global_id variable.
I want to be able to use all the CCSprite constructors such as spriteWithImageNamed along with all the other functions CCSprite has, the problem is that my instance_id isn't being assigned/incremented properly(It's always 0), and I don't really know where to start to fix this.
Here is what I have:
Monster.h:
#import "CCSprite.h"
#interface Monster : CCSprite
#property (nonatomic, readonly) int instance_id;
#end
Monster.m:
#import "Monster.h"
static int global_id = 0;
#implementation Monster:CCSprite
#synthesize instance_id;
-(id) init{
self = [super init];
if(self){
instance_id = global_id;
global_id++;
}
return self;
}
#end
Is the init function called every time any constructor is called? (eg spriteWithImageNamed)?
How do I ensure my extended properties and variables are applied when I call the parent class's functions?
In Objective-C, a class's designated initializer is the one that other initializers are supposed to call into. For many classes, this is indeed init. According to the Cocos2D documentation, however, init is not the designated initializer for CCSprite. Instead, the designated initializer is:
- (id)initWithTexture:(CCTexture *)texture rect:(CGRect)rect rotated:(BOOL)rotated
So that is the method you need to override if you want all the other initializers to call your version.
(If you want to confirm for yourself that this works, you can put a log statement or breakpoint in your implementation of the designated initializer, then call other initializers and make sure the designated initializer is called.)
Your init method may or not be called depending on what init these factory methods are using internally. For example, initWithFile may call self = [super init] instead of self = [self init], in which case your implementation will not be called. You can ensure that your initialization is always performed by overriding all init methods of all superclasses and do your necessary setup. Also keep in mind that you can also override any of the factory methods, where you can get the object from calling super, and then assign it's id property before returning.
looking at CCSprite it seems that every factory method like +(id)spriteWith* calls an initWith* method
and every initWith* method at the end of the chain calls [self init]
so if you override the init method as you do in monster.m you are ok!
by the way, if you want to create your sprite using a factory method do not call [CCSprite spriteWith*], call [Monster spriteWith*] instead
best regards

Can subclass override non-public methods

I have two classes: BatchDownloader, SpeechDownlader
BatchDownloader is the base class, and SpeechDownloader inherited it.
In BatchDownloader, whenever one file was downloaded, -(void)downloadComplete:task will be called.
But in SpeechDownloader, I also want to post a notification in downloadComplete:task.
Can I just write the method with the same name in SpeechDownloader's implementation ? or there is a better way ?
Thanks.
p.s. I don't want to make -(void)downloadComplete:task public, because it should only be called by itself.
If you implement a method in a subclass that has the same name as a private method in a superclass, your subclass method will be called on instances of your subclass.
i.e., if you implement a method in your superclass like this, without declaring it anywhere:
#implementation classA
- (void)doSomething {
NSLog("a");
}
Then, in your subclass implementation, implement a method with the same name:
#implementation subclassOfA
- (void)doSomething {
NSLog("b");
}
When you call doSomething on an instance of your subclass, the subclass implementation will be called instead of the superclass implementation, so the code in this example will result in "b" being printed to the console.
However, if you also want to access the superclass implementation of the method, you can use:
- (void)doSomething {
[super doSomething];
NSLog("b");
}
This will also call the superclass implementation. If you get a compile error (due to the method being private and super not appearing to implement it), you can use [super performSelector:#selector(doSomething)] instead to do exactly the same thing.
This happens because of the way the Objective-C runtime looks up method calls. Since these methods have exactly the same method signature (same name, return type and arguments [none]), they are considered equal, and the runtime always checks the class of the object before looking in superclasses, so it will find the subclass method implementation first.
Also, this means you can do this:
classA *test = [subclassOfA new];
[test doSomething];
And, surprise surprise, the console will print "b" (Or "a b" if you called the super implementation too).
If you implement the method with the same method signature it will be called faith your implementation, public or not.

Recommended instance variables initialization place for Cocoa Touch classes

I'm feeling very stupid, but...what is the right way to init instance variables in custom types, derived from Cocoa Touch UI classes?
Say I have type, derived from UIViewController, let it be TRUIController.
I defined an ivar as follows:
#implementation TRUIController
{
NSNumberFormatter *_numberFormatter;
}
#end
And where should I put _numberFormatter initialization code, if I want it to be executed before any UI methods like viewDidLoad, etc?
In other languages I would create constructor, call base constructor and then init my ivars.
But that simply does not work in objective-c and Cocoa Touch.
In case described above,
If I write
-(id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibBundleOrNil bundle:nibBundleOrNil];
if(self)
{
//init ivars
}
return self;
}
It won't work, I'll try other initWithBlaBla methods, and finally find init, which is actually called, in that case - initWithCoder:
Now, let's say I have class, derived from UITableViewCell. Again, need to init NSNumberFormatter ivar. Why can't I just override init:, call super and init my ivars?
What's the idea behind this strange design decision not to have single common initialization method for all types?
Is it the only way to initialize ivars in derived types? Every time do some research to figure out what method to override this time?
Have I missed something? Because it feels extremely stupid/unintuitive/error-prone
You have to do so overriding the designated initializer.
From the official documentation
A designated initializer is an init method of a class that invokes an
init method of the superclass. (Other initializers invoke the init
methods defined by the class.) Every public class should have one or
more designated initializers. As examples of designated initializers
there is NSView’s initWithFrame: and NSResponder’s init method. Where
init methods are not meant to be overridden, as is the case with
NSString and other abstract classes fronting class clusters, the
subclass is expected to implement its own.
Designated initializers should be clearly identified because this
information is important to those who want to subclass your class. A
subclass can just override the designated initializer and all other
initializers will work as designed.
When you implement a class of a framework, you often have to implement
its archiving methods as well: initWithCoder: and encodeWithCoder:. Be
careful not to do things in the initialization code path that doesn’t
happen when the object is unarchived. A good way to achieve this is to
call a common routine from your designated initializers and
initWithCoder: (which is a designated initializer itself) if your
class implements archiving.
Read the documentation for finding out which initializer is the designated one and override it.
According to the documentation of UIViewController initWithNibName:bundle: is the designated initializer for this class is so you should override that one, but if you are not programmatically instantiating your class (e.g. you're loading it from nib/storyboard) you have to override the archiving method initWithCoder:.
As suggested by the documentation you can create a routine for initialization and call it from both the designated initializer and the archiving method.
It generally makes sense to use the designated initializer as a starting point, but if you are not sure this is always the one that will be used that won't make all that much sense.
Personally I therefore prefer to create a setup method which is called from any init-method I know is likely to be used at some stage. For ViewControllers I normally call the setup method from viewDidLoad instead (unless of course there's any state that's needed before this stage).

Should subclasses call the designated initializer in the immediate super class?

I've seen some sample code which has got me wondering about calling the designated initializer in the super classes. Say I have some code this:
#interface NewTableViewCell : UITableViewCell {
}
#end
#implementation NewTableViewCell
- (id) initWithFrame: (CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
// Do some stuff
}
return self;
}
#end
Note that initWithFrame is the designated initializer for UIView, not UITableView. Should this code always be calling [UITableViewCell initWithStyle:reuseIdentifier:], or does it depend on the coder's intent?
When subclassing, the guideline is that the designated initializer has to call its super class' designated initializer.
Another guideline is that the subclass needs to override the superclass' designated initializer to call the new designated initializer.
If UITableViewCell follows this guideline (and it does; I tested with the help of a category), it overrides its superclass' designated initializer (UIView's initWithFrame:) to call the new designated initializer (initWithStyle:reuseIdentifier:). Therefore, if you call initWithFrame: on UITableViewCell it will call initWithStyle:reuseIdentifier:, which in turn will call initWithFrame: on super (UIView).
Therefore, it will need an additional method call but it will eventually go through initWithStyle:reuseIdentifier:.
Again, the best practice is that the designated initializer has to call the super class' designated initializer and any other initializer that isn't the designated initializer has to call the designated initializer. From "The Designated Initializer":
General principle: The designated initializer in a class must, through a message to super, invoke the designated initializer in a superclass.
Designated initializers are chained to each other through messages to super, while other initialization methods are chained to designated initializers through messages to self.
I agree it depends on the coders attempt but the coder should always try and use the designated initializer. Think about initializers you may have written, they probably do additional work for your object to be in a usable or desired state. If you are overriding an initializer like you are doing in your example you should call the overridden initializer as well. If that was a custom init method then you would want to call the designated initializer because for UITableViewCell's that is the only way to set the reuseIdentifier publicly.
//Override initWithFrame
//Fine although it may not (should not) get called for a UITableViewCell
- (id) initWithFrame: (CGRect)frame {
self = [super initWithFrame:frame];
//Design a custom initializer to gather parameters for supers default initializer
-(id)initWithCustomObject:(id)object style:(UI..Style)style reuseIdentifier:(NSString*)rid {
//This should call initWithStyle:reuseIdentifier:

Initializing a class using superclass initializer

I have got two classes, one a subclass of the other (say Animal and Dog). The superclass has got some initializers (say initAnimal), the subclass has some initializers (say initDog). The problem is that it is perfecly legal (from the compiler’s viewpoint) to do something like Dog *adog = [[Dog alloc] initAnimal], ie. initialize a class using its superclass initializer. I do not like this, because the subclass can have some extra instance variables that I want to make sure are initialized. A look into the header file solves this, but is there a simple way to make the compiler check for me? I have got a feeling I am missing something terribly obvious, but I just can’t put my finger on it :-)
Update: The initDog and initAnimal were not the best examples. I meant two really different initializers (like init for Animal and initWithFur for Dog). If I wanted every dog to have some fur assigned, I would have made the fur part of the initializer, so that nobody could obtain a dog object without a fur. But then it’s still easy to mistakenly initialize the instance with the superclass init, and then I’m hosed.
Thanks for bringing up the designated initializers, Jason. It did not occur to me before, but I could overload the designated initializer of the superclass and set some sane defaults there. But I would still prefer if I could somehow make it illegal to use other initializers than those of the class itself – any more ideas?
Generally in Objective-C you create a designated initializer for each class and then subclasses use the same initializer. So instead of using initAnimal and initDog, you just use init. The dog subclass would then define its own init method and call the designated initializer in its parent class:
#implementation Dog
-(id)init
{
if( (self = [super init]) ) { // call init in Animal and assign to self
// do something specific to a dog
}
return self;
}
#end
You don't really have to specify initDog and initAnimal because the class is declared on the right hand side of the assignment...
Update: I'm adding the following to the answer to reflect the additional information in the question
There are a number of ways to ensure that subclasses don't call initializers other than their designated initializer and the way you ultimately choose will be largely based on your whole design. One of the nice things about Objective-C is that it's so flexible. I will give you two examples here to get you started.
First, if you create a subclass that has a different designated initializer than its parent class, you can overload the parent's initializer and throw an exception. This will let programmers know immediately that they've violated the protocol for your class... however, it should be stated that you should have a very good reason for doing this and that it should be very well documented that the subclass may not use the same initializer as the superclass.
#implementation Dog
-(id)init
{
// Dog does not respond to this initializer
NSAssert( false, #"Dog classes must use one of the designated initializers; see the documentation for more information." );
[self autorelease];
return nil;
}
-(id)initWithFur:(FurOptionsType)furOptions
{
if( (self = [super init]) ) {
// do stuff and set up the fur based on the options
}
return self;
}
#end
Another way to do it is to have initializer more like your original example. In that case, you could change the default init on the parent class to always fail. You could then create a private initializer for your parent class and then make sure everyone calls the appropriate initializer in subclasses. This case is obviously more complicated:
#interface Animal : NSObject
-(id)initAnimal;
#end
#interface Animal ()
-(id)_prvInitAnimal;
#end
#interface Dog : Animal
-(id)initDog;
#end
#implementation Animal
-(id)init
{
NSAssert( false, #"Objects must call designated initializers; see documentation for details." );
[self autorelease];
return nil;
}
-(id)initAnimal
{
NSAssert( [self isMemberOfClass:[Animal class]], #"Only Animal may call initAnimal" );
// core animal initialization done in private initializer
return [self _prvInitAnimal];
}
-(id)_prvInitAnimal
{
if( (self = [super init]) ) {
// do standard animal initialization
}
return self;
}
#end
#implementation Dog
-(id)initDog
{
if( (self = [super _prvInitAnimal]) ) {
// do some dog related stuff
}
return self;
}
#end
Here you see the interface and implementation of the Animal and Dog class. The Animal is the designated top-level object and therefore overrides NSObject's implementation of init. Anyone who calls init on an Animal or any of Animal's subclasses will get an assertion error referring them to the documentation. Animal also defines a private initializer on a private category. The private category would stay with your code and subclasses of Animal would call this private initializer when they call up to super. It's purpose is to call init on Animal's superclass (NSObject in this case) and to do any generic initialization that might be necessary.
Finally, the first line in Animal's initAnimal method is an assertion that the receiver is actually an Animal and not some subclass. If the receiver is not an Animal the program will fail with an assertion error and the programmer will be referred to the documentation.
These are just two example of how you might design something with your specific requirements. However, I would strongly suggest you consider your design constraints and see if you really require this type of design as it's non-standard in Cocoa and in most OO design frameworks. For instance, you may consider making various animals root-level objects and just have an Animal protocol instead, requiring that all of the various "animals" respond to certain animal-generic messages. That way each animal (and true subclasses of Animal) can handle their designated initializers themselves and won't have to rely on superclasses behaving in such a specific, non-standard manner.