-(id)init using designated initialiser? - iphone

In the past I have always used method_1: but I have recently noticed a few instances where folks have instead called the superclasses designated initialiser. Does it matter, just curious if its more about style or substance?
Method_1:
-(id)init {
self = [super init];
if(self) {
//do things ...
}
return self;
}
Method_2:
-(id)init {
[super initWithNibName:nil bundle:nil];
// do things ...
return self;
}
-(id)initWithNibName:(NSString *)nibName bundle:(NSString *)bundle {
return [self init];
}
cheers Gary

Only a few instances?
The Apple documentation on Designated initialisers has this to say on subclassing:
General Principle: The designated initializer in a class must, through a message to super, invoke the designated initializer in a superclass.
Also:
Designated initializers are chained to each other through messages to super, while other initialization methods are chained to designated initializers through messages to self.
Your method 2 would be correct if:
-initWithNibName:bundle: is the designated initialiser of the super class
-init is the designated initialiser of your class (your example is a bit bizarre since you deliberately throw daway the nib name and bundle parameters)
-init was correctly coded not to throw away the return value from [super initWithNibName: bundle: ]
In your class you have to cover all of the super class init methods to ensure that your designated initialiser ultimately gets invoked.

Neither of the above make any sense for the init methed of a class who's super class has the designated initializer
- (id)initWithNibName:(NSString *)nibName bundle:(NSString *)bundle
What are you trying to do?

The idea of a designated initialiser is that all other initialisation functions of a class should call it (this is only enforced by convention). This is nice as it means that someone writing a subclass can add additional steps to the initialisation while only overriding a single initialisor. When this pattern is being used, method 1 should only happen when init is the designated initialiser. One strategy for ensuring this occurs is as follows:
Suppose C inherits from B and let the designated initialisers be d_c and d_b. We override d_b in C to make it simply call d_c on itself. Since d_b is called by all other initialisers of B, this ensures that all initialisers present in the subclass call d_c. We then make all new initialisers call d_c too. d_c calls d_b in its superclass B, which will then pass the calls further up the chain.
Note that this strategy is the opposite of how classes are often initialised. For example, an initialiser with arguments a:1 b:2 could handle the b argument and then call another initialiser that could handle just the a argument. This works well when the function with arguments a and b is simple, by the designated initialiser works better in more complicated situations.

Related

Difference between self and super

just had a noob question. I'm trying to understand the difference between calling self and super. Now I understand inheritance and other fundamental OOP concepts, but the idea of self and super is still not clear to me. I'll illustrate my question with an example.
So the the below code performs a segue when the phone is tilted upside-down. I understand that "Scene2ViewController" is a subclass of "UIViewController" and so "Scene2ViewController" inherits all of UIViewController's methods. And so below I'm calling the method performSegueWithIdentifier with the receiver of the message being self. Now when I change "self" to "super" the code still executes the same way. Isn't calling super the same as calling self? If someone could explain this to me it would be appreciated, thanks.
//Scene2ViewController.m
- (BOOL)shouldAutorotateToInterfaceOrientation: (UIInterfaceOrientation)interfaceOrientation
{
if (interfaceOrientation == UIInterfaceOrientationPortraitUpsideDown) {
[self performSegueWithIdentifier:#"SegueToScene1" sender:self];
}
return (interfaceOrientation ==
UIInterfaceOrientationPortrait);
}
self and super actually both point to the same object. super is a keyword that tells the compiler to generate instructions that start the search for a method definition in the super class rather than in the current class.
#interface A : NSObject {}
- (void)foo;
#end
#implementation A
- (void)foo {
NSLog(#"A's foo!");
}
#end
#interface B : A
#end
#implementation B
- (void)foo {
NSLog(#"B's foo!");
}
#end
//...somewhere in a method of class B...
[self foo]; // prints "B's foo" in the console
[super foo]; // prints "A's foo" in the console
If we assume, per the comment, that the last lines are somewhere in a method of B, then self points to some instance of B. super also points to that same instance of B. But when you use self to call foo, the search for an implementation of foo starts with class B. When you use super, the search for a foo starts with B's superclass, A.
super is especially handy when you want to preserve the inherited behavior, but add something on. So, we could have B's implementation of foo call A's version using [super foo]. Without super there'd be no way to call the inherited method, and calling foo from the overridden method would result in infinite recursion.
When you call a method of self (or rather send a message to self in Objective-C terms) the runtime will search for an implementation of that method in the inheritance hierarchy, starting with self, going up to NSObject. So if self implemented that method, it will be executed. If not, the super class will be checked and so on.
Sending the message to super is very similar, with the exception that the runtime will start looking for an implementation in super and skip self.
Well sometimes, in a subclass, you might override a function that was already defined in the parent class. Frequently this happens in the init function. So if you need to call the parent class's init function you call super. If you need the subclass' function you call self. If only the parent has the function declared then Self and super act the same. But if only the subclass has the declaration then you cannot call the function from super.

Link superclass init method to designated initializer

Since every class inherits the initializer from the superclass this is how I have linked
the default implementation of init to its designated initializer. (It's working.)
Link:
-(id)init {
return [self initWithItemName:#"Default Value"
valueInDollar:0
serialNumber:#""];
}
Initializer:
-(id)initWithItemName:(NSString *)myItemName
valueInDollar:(int)myValueInDollar
serialNumber:(NSString *)mySerialNumber;
My question is, do I ALWAYS have to link my own initializer the way I did it (Link)?
So WITHOUT the code below own initializers would never be called? Am I right?
-(id)init {
return [self myInitMethod......"];
}
If you only initialize your object with initWithItemName, then you don't have to define the init method at all. The initializers are just ordinary methods (no magic involved), so what you call is what will be invoked. But it is good practice to implement the init method so it can be called and the object will be in a consistent state.

Designated Initializer

-(id)initWithStrAndDate: (NSString *)inString date:(NSDate *)inDate
{
if (self = [super init])
{
[self setStr:inString];
[self setDate:inDate];
}
return self;
}
-(id)initWithStr: (NSString *)inString
{
return [self initWithStrAndDate:inString date:[NSDate date]];
}
-(id)init
{
return [self initWithStr:nil];
I am not sure that I know how to use the "designated initializer". First of all isn't
return [self initWithStrAndDate:inString date:[NSDate date]];
this wrong? Shouldn't this be:
return [self initWithStrAndDate:inString date:nil];
And also why do we use 3 different initializers? I mean when do we use "-(id)init" or "-(id)initWithStr: (NSString *)inString" or the first one?
When a class has multiple initializers one, or sometimes more, of them are defined as designated initializers - these initializers must completely initialize the class and invoke a designated initializer of the super-class so that it is completely initialized.
Other initializers are called secondary initializers and must, via calls to self, end up invoking one of the designated initializers. (See Cocoa Fundamentals - Multiple initializers.)
There are two main consequences of this model:
You avoid code duplication and consequential errors; for most classes one initializer does all the work; and
When sub-classing you only need to override the super-classes designated initializers and primitive methods (the non-initializer method equivalent of designated initializers) as all other methods of the super-class end up calling these. You can of course override more methods and must to do if you need to change the behaviour (see Cocoa Fundamentals - Multiple initializers again.)
So your example is correct - 1 designated initializer and 2 secondary initializers which invoke the designated one via a call to self.
There are 3 different initializers so you can use either one of them - neither one of them is wrong, they allow you to init the class with variable data - mostly for convenience as in the end they all do the same thing.
You may init the class with specified string and date (the first and longest initializer),
or you can specify the string only and have the date be set to current time,
or you can have an empty string and current time.
note that calling:
[self init];
is equal to calling
[self initWithStr: nil];
and this in turn is equal to
[self initWithStrAndDate: nil date:[NSDate date]];
So in the end you are calling the same initializer anyway.
You have one designated initializer read the root initializer or the method that does all the work. The other initializer methods only call this root initializer with default values for the missing parameters.
You use [NSDate date] instead of nil, simply because the current date is your default value.
Which initializer you should use depends on the values you want the object to have set. If you have a string and a date, you use the one with string and date. If you don't have a date, you use the one without the date and just the string, and so on.

What exactly is 'super' doing in my apps?

Ok, this is going to be a really embarrassing question, but I looked like mad in my beginner's books (especially those usually helpful indices) and behold, I did not find a down-to-earth explanation of what 'super' does in my applications.
I had a look at this here, but I'm afraid that's well beyond me. Can anyone offer a very simply explanation of what 'super' does in my apps and why I should become friends with it? E.g.:
- (void)viewDidLoad {
[super viewDidLoad];}
Thanks!!
super calls the superclass's implementation of the method. So if your class inherits UIViewController, then [super viewDidLoad]; will call the UITableViewController class's viewDidLoad method. You should usually do this because the super class may do important things that need to happen. In the case of viewDidLoad, I'm not sure it actually does anything currently, but it always could in a future version of the framework.
at the low level, self contains a pointer to the set methods it responds to. this is a basic mechanism for the implementation of dynamic dispatch. each class is given a unique set. if you're familiar with c++, this is similar in concept to a virtual table. you can think of an objc method as being like a C function with 2 hidden arguments (self,_cmd).
super is a dynamically created representation of self, with a pointer to the next-in-line methods implemented by the instance's superclasses. this representation is based on self, and just directs to another set of implemented methods.
#interface MONTypeA : NSObject
- (void)monMethod;
#end
#interface MONTypeB : MONTypeA
- (void)monMethod;
#end
#implementation MONTypeA
- (void)monMethod {
printf("i am MonTypeA\n");
}
#end
#implementation MONTypeB
- (void)monMethod {
[super monMethod]; /* << will call -[MONTypeA monMethod], which will print "i am MonTypeA\n" */
printf("i am MonTypeB\n");
}
#end
if you create an instance of MONTypeA, then it will respond to monMethod:
MONTypeA * a = [MONTypeA new];
[a monMethod];
[a release], a = 0;
// outputs: "i am MonTypeA\n"
MONTypeB * b = [MONTypeB new];
[b monMethod];
[b release], b = 0;
// outputs: "i am MonTypeA\n""i am MonTypeB\n" because -[MONTypeB monMethod] calls through super
therefore, calling super performs the implementation of the method of the superclass in this specific case.
it is important to remember: the set of methods super refers to is always those of the previous implementation of the method in the hierarchy, it is not the same set as the set of instance methods which an instance of the superclass would be given (unless your class were to override every method).

Should +initialize/+load always start with an: if (self == [MyClass class]) guard?

When implementing an +initialize or +load method in one of your Objective-C classes, should you always start with this kind of guard?:
#implementation MyClass
+ (void)initialize {
if (self == [MyClass class]) {
...
}
}
...
#end
Seems like code in +load and +initialize usually only wants to be executed once. So this would help avoid dupe execution when subclasses load/initialize.
I guess I'm just wanting some reinforcement from some ObjC wizards that this is necessary/common practice...
What's the common wisdom on this? would you recommend always doing this?
Is your advice the same for both +load and +initialize, or is there a difference in they way they should be handled?
thanks.
The quick answer is: No.
An in-depth discussion of this matter can be found on the Apple developer mailing list.
The gist of it is that:
The runtime will actually call +initialize on super classes before it is called on subclasses.
If you do include the guard, subclasses of your class that have their own +initialize method will not trigger dependent KVO notifications.
For an example of point #2, be sure to read this post in the thread mentioned above.
Yes, you should do this in your intialize and load methods if you are initializing globals that should only be initialized once.
That said, there are a number of cases where you may avoid it...
You shouldn't wrap with this conditional if the work needs to be performed on every inheritant of every class:
For example, adding all inherited class names for each class to a set.
edited addition: or you're establishing KVO dependencies (as mentioned by eJames)
There are also situations where you just needn't bother:
If the actions you perform are idempotent (don't change values if repeated)
The class is "sealed" (has no descendants by design)
The "idempotent" part is relevant. An initializer should just be setting the initial state (which should be the same each time). In a good initializer, repetition shouldn't matter. Although I suppose that if you forget to wrap the method in the conditional when it does matter, this might be annoying.
edited addition: A different approach, that properly reflects any initialize-only-once requirements would be to test if your properties to initialize are initialized already. i.e.
id myGlobalObject = nil;
+(void)initialize
{
if (myGlobalObject == nil)
{
myGlobalObject = [[MyGlobalClass alloc] init];
}
}
YES!!!!
Because the initialize method of a class may be invoked many times. e.g. when you implement initialize in parent class, and don't implement in sub class, then you call sub class first, the initialize of parent will invoked twice.
#implementation BaseClass
+ (void)initialize
{
NSLog(#"BaseClass initialize self=%#, class=%#", self, [BaseClass class]);
}
#end
#interface SubClass : BaseClass
#end
#implementation SubClass
// don't implement the initialize method
#end
==================
now when you call SubClass first, just like
[SNSBaseSubLogic alloc]
look the debug console, output:
BaseClass initialize self=BaseClass, class=BaseClass
BaseClass initialize self=SubClass, class=BaseClass
so, you must use
+ (void)initialize
{
if (self == [BaseClass class]) {
NSLog(#"BaseClass initialize self=%#, class=%#", self, [BaseClass class]);
}
}
to ensure the method body execute once.