Link superclass init method to designated initializer - iphone

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.

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.

Objective-c Is super init a class method or instance method?

I am new in objective c. I understand that -init() is an instance method and return an object
e.g. myObj=[myObj init]; will return an object myObj.
However, if self =[super init]; normally super refer to parent class e.g. NSObject which is a class, not instance.
So, Is -init() instance method or class method for super init?
thanks
init is an instance method. The fact that you call it on super does not change it.
Keep in mind that super does not represent the class of your object, but your object seen as an instance of its parent class in the class hierarchy.
And you never call myObj=[myObj init]; — you call myObj = [[MyObj alloc] init]. Notice the case difference between myObj (a variable) and MyObj (the class of which this variable is an instance).
Generally init is used after alloc in this way:
MyObject* obj = [[MyObject alloc] init];
and alloc create the object instance, so init is an instance method, and when you override it, it's good habit to call always the parent class init.
Try to read this article.
Super is referring to the methods of the parent class in the current object. Calling super init will call the method init on the current object (self), but will use the implementation of the super class. So no - init is not a static method (this would be visible due to a + before the init method). you can call super whatMethodYouWantFromSuperclass even though it is not static. Static methods are not called on an object (self) but on a class ([NSObject yourStaticMethod]).

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.

Objective-C - Overriding method in subclass

I am having some trouble figuring out hour to accurately override a method in one of my subclasses.
I have subclass (ClassB) of another customclass (ClassA):
#interface ClassB : ClassA {
}
and within ClassA, there is a method called:
-(void)methodName;
which fires correctly.
However, I need this method to fire in ClassB.
I've tried implementing (in ClassB):
-(void)methodName {
[super methodName];
}
but it still won't fire in ClassB.
How can I override methodName so that it will fire in ClassB?
You just add your custom code in methodName in classB :
- (void)methodName
{
// custom code
// call through to parent class implementation, if you want
[super methodName];
}
First, make sure your init method creates a ClassB object and not a ClassA (or something else) object.
Then, if you want to create a completely different classB (void)methodName: method than the one found in classA, this is the way to go:
Super is the superclass. By calling [super methodName] you're asking ClassA to execute it's own methodName.
If you want to completely override methodName from classA, just don't call super.
So, basically, in your classB's implementation of methodName:
-(void)methodName {
// Remove [super methodName]
// Insert the code you want for methodName in ClassB
}
Feel free to read Messages to self and super in Apple's The Objective-C Programming Language document.
By writing:
-(void)methodName {
[super methodName];
}
You tell the compiler: When executing methodName of Class B, call methodName of its superclass (Class A). So if you want Class B to do something different you have to write code that results in a different behavior. Like this:
-(void)methodName {
NSLog(#"Hello, world!");
}
Now by calling methodName of Class B "Hello, world!" will be printed on the console.
-(void)methodName {
[super methodName];
}
Wanna call methodName (in ClassB), just remove [super method] then you can fire it.
Cause super is call back to ClassA
Although this question is too old, but there are sill some learners as every expert was,
The following is quoted from Apple documentation.
"The new method must have the same return type and take the same number and type of parameters as the method you are overriding."
full answer can be found in Apple method overriding documentation
Hope this helps someone.

-(id)init using designated initialiser?

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.