I have 3 Objective-C classes:
Animal - a subclass of NSObject
Feline - a subclass of Animal
Cat - subclass of Feline
Each of these three classes implement (what I thought was) its own private method (-private_Setup), for setup:
e.g. in Animal:
-(instancetype)init
{
self = [super init];
if (self) {
[self private_Setup];
}
return self;
}
Same thing in the Feline and Cat classes.
A list of required classes is provided at runtime, so I am creating instances of the various classes, depending on a list of class names.
e.g.
NSString *className = ... // #"Animal", #"Feline" or #"Cat".
id animal = [[NSClassFromString(className) alloc] init];
Problem:
If I create an instance of Cat, -private_Setup is being called multiple times, for each step in the inheritance chain. For example, the calling chain for a Cat:
-[Cat init]
-[Feline init]
-[Animal init]
-[Cat private_Setup] // First!
then, from:
-[Feline init]
-[Cat private_Setup] // Second!
then, from:
-[Cat init]
-[Cat private_Setup] // Third!
Thus, what I thought was a method private to each class, is being called after each -init in the hierarchy.
Could someone please advise how I could either fix this issue or redesign my setup strategies? Thankyou.
[edited, appended for clarity]
Some form of setup is required at each level of the inheritance, to supply data particular to that level. e.g. Cat specific settings.
Thus, what I need is for a Cat object to be fully set up as an Animal, as a Feline, and as a Cat.
I guess one approach is to have different setup method names at each level. e.g. setupAnimal, setupFeline, setupCat.
e.g. in Animal:
-(instancetype)init
{
self = [super init];
if (self) {
[self setupAnimal];
}
return self;
}
// in Feline:
-(instancetype)init
{
self = [super init];
if (self) {
[self setupFeline];
}
return self;
}
// in Cat:
-(instancetype)init
{
self = [super init];
if (self) {
[self setupCat];
}
return self;
}
Is there a better, more preferred design than this?
I think you should call private_Setup method just once - in Animal's init. That's all. Implement in all subclasses, call just once in supercalass
You're saying that you need a different form of setup for each subclass. Of course! That's why what you do is you implement private_Setup in every subclass. Implement just like you need it for every particular subclass. It's called overriding. Inside overridden method call [super private_Setup]. You'll get exactly what you need.
You are saying super init and super's init calls private_Setup, so why are you surprised?
I guess you're surprised because you expect each init in the chain to call its own class's private_Setup. But the thing to understand is that meaning of self changes depending on the original class of the instance that started the chain (polymorphism).
So, for example, if you call self private_Setup from Animal's init during the process of initializing a Cat, it is Cat's private_Setup that will be called. Thus, with the arrangement you've made, it is exactly true that on initialization of a Cat, Cat's private_Setup will be called three times and none of the others will be called.
The solution is simple: don't use an extra method. It is a capital mistake to have an initializer call any methods (and the problem you're having is one of the reasons why it's a mistake). Instead, simply perform the setup in init itself. That is what it's for.
If I understand correctly, you are implying that the call to private_Setup happens in all of your subclasses' init methods too.
Remove the call to private_Setup from all but the top (e.g. Animal) init method. As long as all of them call [super init], you'll get exactly one call to private_Setup.
Related
#implementation NVController
//Plain Init method
-(id)init
{
self=[super init];
if(self)
{
}
return self;
}
//CustomInit Method
-(id)initWithRootViewController:(UIViewController *)rootViewController
{
self=[super initWithRootViewController:rootViewController];
if(self)`enter code here`
{
}
return self;
}
#end
NVController *instance=[[NVController alloc] initWithRootViewController:nil];
Here In above case ,Since I call only initWithRootViwController, another constructor init is also called. Any help would be appreciated.
This happens because you did not implement your initializers correctly.
In Objective C there is a concept of designated initializer, a single init function of your class that all other initializers must call. It is the designated initializer that calls [super init] directly; all other initializers need to call [super init] indirectly by invoking the designated initializer.
In your particular case you need to move the code common to both your init and initWithRootViewController:, if any, into the initWithRootViewController: initializer, and rewrite the plain init as follows:
-(id)init {
return [self initWithRootViewController:nil];
}
** EDIT :** (in response to the comment indicating that this solution causes an infinite recursion) I think the reason why you get infinite recursion has to do specifically with implementation details of UINavigationController, which should not be inherited. According to Apple's documentation,
The UINavigationController class implements a specialized view controller that manages the navigation of hierarchical content. This class is not intended for subclassing. Instead, you use instances of it as-is in situations where you want your application’s user interface to reflect the hierarchical nature of your content.
EDIT: The prohibition against subclassing has been lifted in iOS 6 - see the documentation for UINavigationController.
I guess initWithRootViewController: is implemented like this:
-(id)initWithRootViewController:(UIViewController *)rootViewController
{
self=[self init];
if(self)
{
// do something with rootViewController
}
return self;
}
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
why does initializing subclasses require calling the super class's same init function?
I really can't understand the role of super in initializing an object.
For example, having this (example — not written by me) code:
#implementation MyObject
- (id) init
{
if([super init]){
return self;
} else {
return nil;
}
}
#end
What [super init] actually does? I'm confused, can't get the point
It is necessary to ensure correct initialisation of inherited instance variables from the super class of MyObject.
Since Objective-C is object oriented you can inherit from other classes. When you inherit from other classes you can intercept messages and get to decide if you pass them on to the class you inherit from. In the case of init it is almost always important to do self = [super init] or use the designated init method of the class to make sure the object is created correctly. Imagine if in MyObject in your init method you create an NSMutableArray that your class uses but init was never called because someone else inherited from your class and never called [super init]. You would then have nil references or either a bad pointer every where you attempted to used your NSMutableArray. The reason why it is important to set self equal to [super init] is the value of self may change such as in error recovery.
//this is valid
-(id)init
{
if((self = [super init]))
{
if(someInitializationFails)
{
[self release];
self = nil;
}
}
return self;
}
Wil Shipley recommends this (from 2009):
- (id)init;
{
if (!(self = [super init]))
return nil;
// other stuff
return self;
}
But why assign super init's return to self?
Matt Gallagher's article attempts to explain it...
-- Quote:
If you remember back at the start, I
said that the initWithString: part of
a typical [[MyClass alloc]
initWithString:#"someString"]
invocation is converted into an
objc_msgSend call:
MyClass *myObject2 = objc_msgSend(myObject1, initSelector, #"someString");
So by the time we get
to the inside of the method, self
already has a value; its value is
myObject1 (i.e. the allocated object,
as returned from the [MyClass alloc]
call. This is essential because
without it, the super invocation
wouldn't be possible — the self value
is used by the compiler to send the
invocation:
[super init];
becomes:
objc_msgSendSuper(self, #selector(init));
Yes, self already
has a value when your initializer
starts. In fact, it is almost
guaranteed to be the correct, final
value.
-- Unquote
Essentially, I think a lot of people are left confused as to what each init method's 'self' is pointing to exactly, up through the superclass chain.
The answer to this riddle is implied in Apple's Objective-C Programming Language doc, under the section titled Designated Initializers:
Note that B version of init sends a
message to self to invoke the
initWithName: method. Therefore, when
the receiver is an instance of the B
class, it invokes the B version of
initWithName:, and when the receiver
is an instance of the C class, it
invokes the C version.
Or, in other words, the 'self' variable points to the our instance that is being initialized. Again to reemphasize, all of these init methods up through the superclass chain are inherited by our instance, and as such, the 'self' variable in them points to our instance (unless explicitly changed) .
Am I right? Of course!
Disclaimer, I'm new to Objective C. But I can't find this explained. I've seen two ways of implementing init:
- (id)init {
if ([super init]) {
return self;
} else {
return nil;
}
}
and
- (id)init {
if (self = [super init]) {
// do your init business here
}
return self;
}
so let's say i have:
myObj = [[MyObject alloc] init];
where MyObject class is a subclass of NSObject. in the second example, does init not return an initialized version of NSObject? so myObj would ... how would it know what it is? wouldn't it think it was an NSObject rather than a MyObject?
1) First version is just wrong. self should be always assigned with value returned by super initializer, because init<...> of super can return another object upon initialization (it's not unusual BTW). Second version is actually an 'official' way to implement init<...> methods.
2) 'wouldn't it think it was an NSObject rather than a MyObject'. myObj is instance of 'NSObject' and instance of 'MyObject'. It's the whole point of inheritance.
i just want to know, under the hood, how it does it.
It's pretty simple. 99.9% of all the classes you'll ever write will inherit from NSObject in some fashion. In the initializers, you're supposed to invoke super's designated initializer and assign it to self. Eventually, [super init] will be invoking -[NSObject init]. According to the documentation, that's implemented like this:
- (id)init {
return self;
}
So technically, if you inherit directly from NSObject, you're probably safe to not do the assignation of self = [super init];, because you know (and you're guaranteed) that this is equivalent to: self = self;, which is kind of pointless. Regardless, you should leave it in for consistency's sake.
However, once you start getting further down the inheritance chain, and especially when you're inheriting from opaque classes (ie, a class whose .m file you do not have), then things start getting shady. It is possible that you'll come across a class whose designated initializer looks something like this:
- (id) initWithFoo:(id)aFoo {
if ([aFoo isSuperFast]) {
[self release];
return [[SuperFastFooWrapper alloc] initWithFoo:aFoo];
}
self = [super init];
if (self) {
_foo = [aFoo retain];
}
}
This isn't as common, but it does happen. In this case, we're destroying self ([self release], to balance the alloc call that immediately preceded this) and instead returning a different object.
Currently I'm hard coding another object directly when needed and I'd like the ability to take this in through the init method (I assume?). In the code below I create a new HatService in the viewDidLoad method and I'd prefer not to do this this for testability / coupling reasons.
- (void)viewDidLoad
{
[super viewDidLoad];
HatService* hatService = [[HatService alloc] init];
[hatService getHatById:self];
}
First question - How should this be done in objective-c?
Second question - Should I be worried about this or doing it at all?
Update
Here is what I'm starting with but I never seem to hit the first init method during runtime. I have both declared in the interface - anything else I missed that would allow me to override this init method and inject the service dependency?
Note - I can hit this manually when I create the object myself but when the appDeleage does the work I don't see it hit this (how does the app delegate create this object without calling my init method?)
-(id)initWithHatService:(HatService *)service
{
if (self = [super init])
{
[self setService:service];
}
return self;
}
-(id)init
{
HatService* hatService = [[HatService alloc] init];
return [self initWithHatService:hatService];
}
The designated initializer for UIViewController is - (id)initWithNibName:(NSString *)nibName bundle:(NSBundle *)nibBundle. You'll need to override this method if you want your view controller to be properly instantiated from a nib file, if that's what you're trying to do. Without seeing more code, it's impossible to tell, but this method is definitely being called somewhere.
Second, you need to re-write your -init method to look like this:
- (id)init {
return [self initWithHatService:nil];
}
Every init method should call your designated initializer.
Finally, when you're dealing with view controllers, folks usually don't pass in properties in the init method. Instantiate the new controller, then pass it whatever service properties you like.
MyViewController *newContrlr = [[MyViewController alloc] initWithNibName:nil bundle:nil];
newContrlr.hatService = [[[HatService alloc] init] autorelease];
If you're asking how to pass an object to another object's init method, just declare your init method as taking one or more arguments. i.e. - (id) initWithHatService:(HatService *)serv; init methods aren't special in any way except convention in objective-c.
Unrelated: your -getHatById: method is curious. What are the memory management semantics of that? get-prefixed methods are pretty uncommon in Cocoa programs.
It's quite easy to implement the dependency injection design pattern in Objective-C. You could do it manually by creating an 'application assembly' class that defines individual collaborators.
Alternatively, you could use a framework to assist. I recently created a DI container called Typhoon: http://www.typhoonframework.org
Let's say I create my class and its init method. Why should I call and return value of superclass init assigned to self? Which cases it covers?
I would appreciate examples why would I need it for Cocoa superclass and non-Cocoa.
You mean why
self = [super init];
rather than
[super init];
Two reasons:
in initialisation, failure is indicated by returning nil. You need to know if initialisation of the super object failed.
the super class might choose to replace the self returned by +alloc with a different object. This is rare but happens most frequently with class clusters.
Edited in response to Michael's comment:
I can understand why I need to save and return [super init]. But is it just convention and good looking makes us use self as a temporary variable to pass result along?
No. Instance variables are accessed relative to the self pointer, so in the following:
-(id) init
{
self = [super init];
if (self != nil)
{
myBoolIvar = YES;
// The above is an implicit version of self->myBoolIvar = YES;
}
return self;
}
self has clearly got to point to the right block of memory i.e. the one you are going to return.
The other point is that if super init returns different class instance then the rest of the code after that line may not even make sense, lead to memory leaks and crashes, not even talking about the object instantiated from that class.
That could be a problem. If I subclassed NSNumber and [super init] decided to return an NSString (which it could - there's nothing to stop it) that would clearly be a disaster. Whatever super returns from -init must be "compatible" with the subclass in the sense of providing space for ivars and being further subclassible or it's a horrendous bug (unless, of course, the problem is documented). So, in general, you don't need to worry about checking the class. However, do read the documentation. See for instance the section on subclassing NSString in NSString's docs.
I know it is a little bit late for my answer, but I cannot stop myself from posting a link which I found very useful in clearing my doubt about this problem.
Matt Gallagher: What does it mean when you assign [super init] to self?
EDIT: As per the comments, here are the essential points in the link
To understand why self=[super init]; we need to consider many points. Let's tackle it one by one.
What is self
Every method has two hidden parameters: self and _cmd. So the method call
- (id)initWithString:(NSString *)aString
is changed by compiler into a function call like this
id initWithString(id self, SEL _cmd, NSString *aString);
Why do we need self?
The reality is that the compiler uses the self parameter to resolve any reference to an instance variable inside a method.
Suppose that we have a method setValueToZero and value is an instance variable of the class it belongs to, then the implementation
- (void)setValueToZero
{
value = 0;
}
will be converted by the compiler into a function like this
void setValueToZero(id self, SEL _cmd)
{
self->value = 0;
}
Do self already have a value when init is called?
Following is an example of a typical object creation and initialization.
[[MyClass alloc] initWithString:#"someString"]
Here, by the time we get into the initWithString method, self will have the newly allocated object as its value (i.e., the return value from [MyClass alloc]). In fact, it is almost guaranteed to be the correct, final value.
Why self = [super init];?
It is because [super init] is permitted to do one of the three things:
Return its own receiver (the self pointer doesn't change) with inherited instance values initialized.
Return a different object with inherited instance values initialized.
Return nil, indicating failure.
In the first case, assignment has no effect on self. In the third case, the initialization has failed, self is set to nil and it is returned.
The reason behind assignment to self is with the second case. Consider the following
- (id)initWithString:(NSString *)aString
{
self = [super init];
if (self)
{
instanceString = [aString retain];
}
return self;
}
We want the conversion from
instanceString = [aString retain];
to
self->instanceString = [aString retain];
to act on the correct value and thus we have to change the value of self.
When would [super init] return a different object?
In one of the following situations
Singleton object (always returns the singleton instead of any subsequent allocation)
Other unique objects ([NSNumber numberWithInteger:0] always returns the global "zero" object)
Class clusters substitute private subclasses when you initialize an instance of the superclass.
Classes which choose to reallocate the same (or compatible) class based on parameters passed into the initializer.
In all but the final case, continuing to initialize the returned object if it changes is a mistake — the returned object is already completely initialized and isn't necessary related to your class anymore. So a better init approach will be as follows
- (id)initWithString:(NSString *)aString
{
id result = [super init];
if (self == result)
{
instanceString = [aString retain];
}
return result;
}
Conclusion
You don't need to assign [super init] to self to make most classes work. In some obscure cases, it is actually the wrong thing to do.
So why do we continue to assign to self? It's the traditional template for an initializer, and although it's wrong in some cases, it is right in other cases which have been written to expect this approach.
Basically every Objective-C class is a subclass. It's either some class you've specified or NSObject.
In the subclass (your class that you're working on) you call
self = [super init]
What this basically does is calls the super class's (the ones I mentioned above) init method (the constructor) and assigns it to the current class.
This makes sure that the superclasses' initializing method is called.
Now for
If(self)
This basically checks if the above piece of code worked.
This is done to insure that if you call some Instance Variable of the super class, you'll be able to do so.
In most cases, setting self to [super init] does nothing since [super init] will wind up returning self anyway. There are some rare cases, however, where [super init] will return something different. It may return nil if it fails to initialize the superclass for some reason or it may decide to return a completely different object.
Source
Implementing The Designated Initializer
**
self
**
Inside a method, self is an implicit local variable. There is no need to declare it, and it is automatically set to point to the object that was sent the message. (Something like this in Android programming.) Typically, self is used that an object can send a message to itself. Example here:
return self;
**
super
**
When we overriding a method, we want to keep what method of the superclass is doing and have your subclass add something new on that. To make it easier, there is compiler directive in Objective-C called super.
How does super work? Usually when you send a message to an object, the search for a method of that name starts in the object's class. If there is no such method, the search continues in the superclass of the object. The search will continue up the inheritance hierarchy until a suitable method is found. (If it gets to the top of the hierarchy and no method is found, an exception is thrown).
When we send a message to super, we are sending message to self, but the search for the method skips the object's class and start at the superclass. In the above case, we send init message to super. This calls NSObject's init method.
Because you have to initialize the object somehow, and presumably you want to do any initialization a superclass required be done, since you're descending from it.