self is a hidden instance variable that points to the current object:
- (id) initWithAmount:(double)theAmount forBudget:(Budget *)aBudget{
if(self = [super init]){
budget = aBudget;
amount = theAmount;
}
return self;
}
is it similar to
this.budget=super.aBudget;
this.amount=super.theAmount;
Normally:
if(control)//true or false
{
//stmts will get executed
}
but instead of returning a true value here the self is assigned with super. Why is it so?
Is it similar to constructor. How to use constructors(default,parameterised and copy) in objective C?
Because an assignment expression also returns the result of the assignment,
if (self = [super init]) { ...
is equivalent to:
self = [super init];
if (self) { ...
And since if does not just test pure boolean values but treats everything that is non-zero, non-NULL or non-nil as true, the if statement tests if self is nil after the assignment.
When we write our own init methods, we are supposed to assign [super init] to self because a init method is free to return a different object than the receiver of the method. If we just called [super init] without assigning it to self, we might initialize a different object than self, which is clearly not desirable.
This form is just the short form of the following code:
- (id)initWithAmount:(double)theAmount forBudget:(Budget *)aBudget {
self = [super init]; // you must do this, because every object inherits all properties
// from the parent class, and they must be initialized
// init can return nil if there was an error during the initialization
// so if the parents initialization failed, there is no point of initializing
// the child object
if (self != nil) {
budget = aBudget;
amount = theAmount;
}
return self;
}
It's the way initializers are defined in Objective-C. It's part of the two-stage creation pattern: seperating memory allocation and initialization of the object. As self references the object instance where the initializer resides in it has to go up the inheritance tree and set what they return to itself, after that it's your turn.
The call of super is only used in the designated initializer. You could have more initializers which should always use the designated initializer.
The pattern
- (id)init {
self = [super init];
if (self) {
// code
}
return self;
}
Is the correct way to handle failures. The test will fail if self = [super init]; returns nil: An error occured in initializers up the inheritance tree, so you don't want to use a failed initialization and skip your own code.
Related
My class A is initialised like that:
- (instancetype)init // designated initializer
{
self = [super init];
if (self) {
[self setup]; // just sets some properties
}
return self;
}
I have the following class B which subclasses A:
- (instancetype)init
{
self = [super init]; // calls the initializer of A and SHOULD call the setup code of A but it does not
if (self) {
[self setup]; // just sets some properties for B
}
return self;
}
My Problem:
B should call A's setup method but it does not due to the dynamic typing of Objective-C. Instead B calls its setup code twice.
How can I resolve this problem (besides renaming the methods) or even better ARE THERE ANY BETTER APPROACHES?
I could move the code written in setup to init but the problem is that I have more than one designated initializer (for example: UIViewControllers has initWithFrame: and initWithCoder:) and I am lazy about writing code twice.
I'm not sure why you reject renaming the methods. It's a simple solution.
Another approach is to use functions instead of methods. Functions are dispatched statically, not dynamically.
For example, in the implementation of A:
static void setup(A* self)
{
self.someProperty = /* ... whatever ... */;
}
- (instancetype)init // designated initializer
{
self = [super init];
if (self) {
setup(self); // just sets some properties
}
return self;
}
Likewise for B.
In a function, self doesn't have any special meaning, so it's just a local variable name. You could use a different one, if you prefer.
Assuming the function is inside the #implementation, it has full access to the object, including to private instance variables. So, setup() could use self->_someProperty instead of self.someProperty.
What about a simple approach? Make setup in B call [super setup] and don't call setup in B.
I am attempting to override the init method of a class so that initializing the object also initializes the ivar object:
-(id)init
{
if (self = [super init])
{
someIVarObject = [SomeClass alloc] init];
}
return self;
}
1) Would this code even work, and even so, is this solution discouraged?
2) Why is the if condition not == ? Is it an assignment? If so, why the if?
Sorry if this is obvious! >_<
Yes, it would work, and afaik it's still the way it should be done.
What it does is to call [super init] and allows it to do one of three things;
Return self (ie the same object self is already set to.
Return an entirely new object.
Return nil for failure.
The result is then assigned to self, which makes sure that the rest of the constructor operates on the correct object in case it changed. The if is there to catch the case where [super init] returned nil, in which case the rest of the constructor should be skipped.
1) Here you are declaring a local variable someIVarObject. You should have declared this within the interface or implementation of your class in curly braces, and should then assign it as someIvarObject = .... An example:
#implementation MyClass {
SomeClass *someIvarObject;
}
- (id)init
{
if(self = [super init])
{
someIvarObject = [[SomeClass alloc] init];
}
return self;
}
#end
2) It is an assignment. There is a long history behind this idiom but it mostly comes down to handling the possibility that [super init] returns a different object than init was originally invoked upon.
This...
if(self = [super init])
will work, but it will give you a compiler warning (unless you've turned off this warning).
You can also suppress the warning by using double parenthesis:
if((self = [super init]))
My current preference:
self = [super init];
if(self)
You've got some typos, unbalanced brackets, and the thing you say is an ivar is not an ivar (you declare it inside the if, which makes its scope local to that block. You want to put instance variables in the {}s after your #implementation or #interface declarations). But yes, this is generally how this would work.
However, I'd take a hard look at whether you really need an ivar or not. I can't remember the last time I used one in my code. 99% of the situations I used to use them in, a #property is now a much better solution.
As an added benefit, #propertys synthesize their own getters and setters, (usually) obviating the need to write manual allocing boilerplate, thus making this question moot.
1) this code will work but this line:
SomeClass *someIVarObject = [SomeClass alloc] init];
makes a little sense. Declare SomeClass *someIVarObject in .h file and initialize it in init like this:
someIVarObject = [SomeClass alloc] init];
2) this line if (self = [super init]) is equivalent to:
self = [super init]; if (self != nil)
i.e. it ensures that init method of the base class has returned a proper value
New to objective-c. Wrote a code-snippet to better understand the init mechanism, and ended up with a few questions.
#implementation MyClass
-(id) init
{
if (self) {
i = 5;
NSLog(#"self before init - %# %p i=%d",[self className], &self, i);
} else {
NSLog(#"self is null???");
}
id someClass = [super init];
NSLog(#"the result of super-init - %# %p",[someClass className], &someClass);
self = [super init];
if (self) {
NSLog(#"self after init - %# %p %d",[self className], &self, i);
} else {
NSLog(#"self is null???");
}
return self;
}
i is a private instance variable int.
Here is the result:
2012-12-14 18:01:26.403 Init[1621:303] self before init - MyClass 0x7fff5fbff848 i=5
2012-12-14 18:01:26.405 Init[1621:303] the result of super-init - MyClass 0x7fff5fbff838
2012-12-14 18:01:26.405 Init[1621:303] self after init - MyClass 0x7fff5fbff848 5
What really surprised me is that that someClass's class Name is MyClass.
How does NSObject know to return the sub-classes instance (not just the type match, it is the exact same object)?
I'm aware that it is not good form to call init many times, and initialize instance variables before calling init but I was just experimenting.
Thanks.
You do need to use the standard schemen (more or less):
-(id)init {
self = [super init];
if (self) {
// Do initialization stuff
}
}
Your class subclasses some other class. The call to super init runs the init routine of your superclass. Without it your class is not properly initialized and may malfunction strangely. (However, it's probably not wise to call super init twice, as this could have bad side-effects.)
There are cases where you would not call super init, but would instead call a version of init in your own class. Basically, if you have initWithJunk: and init, you can have initWithJunk: call [self init] instead of [super init] so that the stuff that self init would do gets done and doesn't have to be reproduced in initWithJunk:.
This is especially critical if you write a "category" that adds an init... method to an existing class -- you must call some version of [self init] to assure that the base class's initializer runs.
Understand that the super init method is not (usually) replacing the existing instance with a new one, but rather is initializing instance fields in it that belong to the superclass. The reason for receiving the "self" value back from the super init call is two-fold:
The init routine can return a nil in the event that some sort of error occurs.
In some (rare) special cases the init routine may replace the supplied instance with a different one (eg, a cached version).
As follow-up of sorts to Is returning nil from a [[class alloc] init] considered good practice?, there's a case that I haven't seen any discussed much: what to do with an init that fails some preconditions before it can call the next init?
Example, suppose in this initWithStuff: method being passed nil or in general having no value to pass to initWithValue: is an absolute failure and we definitely want to return nil.
- (id)initWithStuff:(Stuff *)inStuff {
if (!inStuff || ![inStuff hasValidValue])
{
// can't proceed to call initWithValue: because we have no value
// so do what?
return nil;
}
NSInteger value = [inStuff integerValue];
return [super initWithValue:value];
}
Perhaps a clearer example is if the designated initializer method we wrap takes an object pointer and throws an exception if its passed nil. We definitely need to short-circuit that init call that would cause an exception.
My guess: init by any means possible, and only then release self before returning nil. If necessary, call bare init or any other initializer that will work to finish putting self into a known state before releasing it.
// can't proceed to call super's initWithValue: because we have no value
// so do what? do this:
self = [super init]; // or initWithValue:0
[self release];
return nil;
And if there were no such initializer that will work without valid data, I guess one would need to construct some valid, dummy data. Or complain to its author and until then just return nil and live with the leak :^)
Also, how does ARC affect the situation?
My guess: still finish init by any means possible, then just return nil. You'd think setting self might be redundant, but in some cases it's not. In any case, it but it needs to be there to silence a compiler warning.
// can't proceed to call super's initWithValue: because we have no value
// so do what? do this:
self = [super init]; // finish init so ARC can release it having no strong references
return nil;
Are my guesses wrong in any way?
Ideally, if a precondition fails, you don't call [super init…]. You just release self (if not using ARC) and return nil:
- (id)initWithStuff:(Stuff *)stuff {
if (!stuff || ![stuff isValid]) {
[self release]; // if not using ARC
return nil;
}
if (self = [super init]) {
// initialization here
}
return self;
}
The release takes care of deallocating self under MRC. Under ARC, the compiler will insert the release for you.
However, there is a potential problem with this approach. When you release self (or when ARC releases it for you), the system will send the dealloc message to the object. And your dealloc method will call [super dealloc]. You could suppress the [super dealloc] under MRC, but you can't avoid it with ARC.
So the danger is that your superclass might assume that one of its instance variables has been initialized, and rely on that initialized value in its dealloc. For example, suppose this is the superclass:
#interface SomeSuperclass : NSObject
#end
#implementation SomeSuperclass {
CFMutableBagRef bag;
}
- (id)init {
if (self = [super init]) {
bag = CFBagCreateMutable(NULL, 0, &kCFTypeBagCallBacks);
}
return self;
}
- (void)dealloc {
CFRelease(bag);
}
#end
The problem here is that CFRelease requires its argument to not be nil. So this will crash during deallocation if you don't call [super init] in your subclass.
Given this problem, I have to change my initial recommendation. If you know that your superclass's dealloc doesn't have this sort of problem (because, for example, it checks pointers before dereferencing them or passing them to CFRelease), then you can safely not call [super init].
If you don't know that your superclass's dealloc is safe, then my recommendation is that you move your preconditions out of init and into a class factory method.
In other words, don't treat alloc/init as part of your class's public interface. Provide a class method for creating instances:
// The class factory method. Declare this in your header file. This is how you
// or any user of this class should create instances.
+ (id)myObjectWithStuff:(Stuff *)stuff {
if (!stuff || ![stuff isValid])
return nil;
// self here is the class object, so it's appropriate to send `alloc` to it.
// You don't want to hardcode the class name here because that would break
// subclassing.
return [[self alloc] initWithStuff:stuff];
}
// This is now considered a private method. You should not declare it in your
// header file, though in Objective-C you can't prevent the user from calling it
// if he's determined to.
- (id)initWithStuff:(Stuff *)stuff {
// Precondition was already checked in myObjectWithStuff:.
if (self = [super init]) {
// initialization here...
}
return self;
}
I am studying from the Stanford CS193P from Paul Hegarty. Then I see something like this, which I also see other people using:
- (id)init
{
self = [super init];
if (self) {
[self someSetupFunctions];
}
return self;
}
Isn't that redundant? Why not just use:
- (id)init
{
self = [super init];
[self someSetupFunctions];
return self;
}
I thought that messages to nil just fizzle, so why not use this second format?
You may want to do other things than passing messages to self. For example:
- (id)init
{
self = [super init];
if (self) {
// set up ivars
_anIvar = 5;
}
return self;
}
What's really meant by [self someSetupFunctions] is some initialization code, not just a single method call, and a number of important things will fail if self is nil. Most notably, attempting to assign initial values to instance variables will crash.
The self = [super init]; if (self) test is because some initialisers will return different objects, including nil if it's impossible to create an object that satisfies the condition required by the initialiser.
In your own initialiser you need to defend against the superclass doing that, because if you try to access an instance variable on nil you're definitely doing the wrong thing (whether it crashes as a result or not: it usually will).