PDA

View Full Version : Stuck on this code Obj-C




larswik
Jun 13, 2011, 01:24 PM
Objective-C for Absolute Beginners by Apress is great in some areas and horrible in others. It spent almost 4 pages on Boolean Logic (easy stuff) and spent 1/2 page on the code bellow.

- (id)initWithName:(NSString *)newName atFrequency:(double)newFreq {
self = [super init];
if (self != nil) {
name = newName;
frequency = newFrequency;
}
return self;
}


1. The first line is the METHOD with a return type 'id'? The book says id is a generic object. It looks like it is INITIALIZING this generic object with 2 parameters, newName and newFreq. But I don;t see it ALLOC any memory for this new object to store it?

2. Second line - self = [super init]; The book says that this is common stuff and super is short for super class, but I don't understand what it is doing?

3. line 3 I get, I think. The IF statement seems to be checking if self was created or not. Then assigning name and freq with newname and newfreq.

4. It then returns self?

I am taking a stab in the dark here. This Method is creating a new generic object that contains 2 items (or methods) that are 'NewName' and 'New Frequency'. The return self means that once this method received a message it is returning an object (not from a class, but from this method) that can be used.

Am I close in understanding it?

-Lars



mydogisbox
Jun 13, 2011, 02:07 PM
1. From Cocoa Programming by David Chisnall: "The *id* type is roughly equivalent to the void* type in C, with the extra condition that the pointee must be an object." So basically it's an object pointer. In this case it's pointing to the class instance that is being created. Without any more context, I would guess that the parent class allocates all needed memory.

2. This calls the parent class constructor. The current class must be inheriting its functionality from some other class and the init functionality of that other class needs to be called first. Do you understand inheritance?

3. Correct.

4. It returns self because, on the init line, self is reassigned, so the caller may no longer have a reference to the correct object.

I am taking a stab in the dark here. This Method is creating a new generic object that contains 2 items (or methods) that are 'NewName' and 'New Frequency'. The return self means that once this method received a message it is returning an object (not from a class, but from this method) that can be used.

The object isn't generic, it has a type, but we can't discern what type it is from this snippet, because we don't know of what class this method is a part. The method initializes two member variables (not methods) to the passed in values. As before, the caller may have a reference to the object, but initializing it may change the reference the caller should use.

Am I close in understanding it?

Yep.

jared_kipe
Jun 13, 2011, 02:08 PM
Objective-C for Absolute Beginners by Apress is great in some areas and horrible in others. It spent almost 4 pages on Boolean Logic (easy stuff) and spent 1/2 page on the code bellow.

- (id)initWithName:(NSString *)newName atFrequency:(double)newFreq {
self = [super init];
if (self != nil) {
name = newName;
frequency = newFrequency;
}
return self;
}


1. The first line is the METHOD with a return type 'id'? The book says id is a generic object. It looks like it is INITIALIZING this generic object with 2 parameters, newName and newFreq. But I don;t see it ALLOC any memory for this new object to store it?

2. Second line - self = [super init]; The book says that this is common stuff and super is short for super class, but I don't understand what it is doing?

3. line 3 I get, I think. The IF statement seems to be checking if self was created or not. Then assigning name and freq with newname and newfreq.

4. It then returns self?

I am taking a stab in the dark here. This Method is creating a new generic object that contains 2 items (or methods) that are 'NewName' and 'New Frequency'. The return self means that once this method received a message it is returning an object (not from a class, but from this method) that can be used.

Am I close in understanding it?

-Lars

Good question.

1) all init methods are instance methods, meaning they operate on an already alloc'd instance of an object. You can visually see this because they have a - sign in-front of the method name. If it had a + then you would call it directly on the class.

This method would usually be used like this.

MyClass *instance = [[MyClass alloc] initWithName: @"name" atFrequency: 1.0];


2) When dealing with Objects and their inheritances, when you override a method you typically want to call the super classes version of the same method. ESPECIALLY with init and other default NSObject methods.

Lets say we had a superclass that draws a box on the screen, and we make a subclass that draws the same box but puts a little black X in the corner to close or hide the box. The superclass has a method -draw



- (void) draw {
[super draw]; // draws box
/* code that draws X here */
}


The pattern is to not reinvent the wheel, use the super classes methods inside your own, and then add your own functionality.

In the case of init, and the return type of id, sometimes [super init] will return a different object that the original one created in +alloc, this is rare, and you should treat this as voodoo or magic, and just cargo cult use these lines in your own init methods.

3) and 4) You check if self has a value, namely if it is nil you don't bother trying to assign the ivars.
Returns self, even if self is nil. This is why assignment is often done after init.

Usually you could have this code.

MyClass *instance = [MyClass alloc];
[instance initWithName: @"name" atFrequency: 1.0];

And it would perform exactly like the earlier segment....
Unless [super init] or even your own -init method returned some other object. (I believe that the "self =" will not save you and "instance" will point to some uninitialized object somewhere on the heap, and the new object will also be on the heap with a retain count of one)

jared_kipe
Jun 13, 2011, 02:13 PM
1. From Cocoa Programming by David Chisnall: "The *id* type is roughly equivalent to the void* type in C, with the extra condition that the pointee must be an object." So basically it's an object pointer. In this case it's pointing to the class instance that is being created. Without any more context, I would guess that the parent class allocates all needed memory.

2. This calls the parent class constructor. The current class must be inheriting its functionality from some other class and the init functionality of that other class needs to be called first. Do you understand inheritance?


This is not 100% true, the class method +alloc initializes all of the memory.

A good example of where -init... doesn't return the same object is NSArray.
To the best of my knowledge NSArray always returns some other instance on init.

NSNumber is another one, if you init with some low integers it will return a previously created instance for speed and efficiency. Immutable objects are funny that way...

jiminaus
Jun 13, 2011, 04:50 PM
Objective-C has an explicit two-step process for creating an object: allocation and initialisation.

First you send the alloc message to a class in order to get a block of memory big enough to hold an object of the class. It's equivalent to a malloc call in C.

Second you send the init message (or a message beginning with init) to the newly allocated object to initialise the object.

For this reason, I avoid terms like create and the term constructor in Objective-C. I only think of allocating and then initialising an object. I only think of the init and init-like methods as initialisers.

There's a convention in Objective-C that an initialiser will return nil if it cannot successfully initialise an object. In your own initialisers, you need to check if the superclass's init method failed and returned nil. In this case, you must not continue to initialise the object. Why? Because not only does the convention say that an initialiser returns nil when it fails, it also frees the memory block that was allocated for the object. If you continue to initialise an object after the superclass's init fails, you will write to freed memory, cause subtle memory corruption.

For reference: this is documented in the Allocating and Initialising Objects (http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjectiveC/Chapters/ocAllocInit.html) chapter of Apple's The Objective-C Programming Language guide.

Sydde
Jun 14, 2011, 04:31 PM
First you send the alloc message to a class in order to get a block of memory big enough to hold an object of the class. It's equivalent to a malloc call in C.
Except that it is actually equivalent to a calloc, because I believe Apple's documentation says all ivars have and initial value of nil/zero/false.

jiminaus
Jun 14, 2011, 08:35 PM
Except that it is actually equivalent to a calloc, because I believe Apple's documentation says all ivars have and initial value of nil/zero/false.

I was just trying to tie it back with the OP newly acquired C knowledge.

While it closer to calloc than malloc, it's truthfully equivalent to neither because the isa pointer is initialised in alloc.

larswik
Jun 17, 2011, 01:14 AM
Thanks for the replies everyone. I have been gone for the last couple days so a delay in my response.

1) I do understand inheritance - Although I did not write the NSLog method I can still use it because it is written in the super class I defined from my class.

2) Question - When I initialize an Object from my class, does that then force the super class to also allocate and initialize it's self to be used? If so would there be 2 classes 'myObject' & 'super class Object' and so on depending on the number of super classes, or will my 1 object contain everything from it's 1 object? Simply, is 1 object created or many objects created?

I am going to move forward in the book. I kind of get the concept of self now.

Thanks!

-Lars

jiminaus
Jun 17, 2011, 02:03 AM
1) I do understand inheritance - Although I did not write the NSLog method I can still use it because it is written in the super class I defined from my class.


Yes, but NSLog is not a method, it's a function. That's why you write NSLog(blah blah) and not [something NSLog blah blah]. A better example is the description method. You can call description without having defined it in your own class, because NSObject defines it.


2) Question - When I initialize an Object from my class, does that then force the super class to also allocate and initialize it's self to be used? If so would there be 2 classes 'myObject' & 'super class Object' and so on depending on the number of super classes, or will my 1 object contain everything from it's 1 object? Simply, is 1 object created or many objects created?


You get one object. The object will include all the instance variables of all the ancestor classes and as well as the instance variables defined in the class itself.

So say NSObject defines one instance variable calls isa. Say MyClasssA inherits from NSObject and defines two instance variables called a1 and a2. Say MyClassB inherits from MyClassA and defines another instance variable b.

The result of [MyClassB alloc] will be a single memory block big enough to hold all of isa, a1, a2 and b.

When you call init on the MyClassB object, the first statement in MyClassB's init should be:

self = [super init];


So now we're in MyClassA's init and the first line of the MyClassA's init should be:

self = [super init];


So now we're in NSObject's init. NSObject is a root class, so it won't call super init. But what it will do is initialise its and only its instance variable, isa.

Then then we return to the rest of MyClassA's init. There MyClassA will initialise its and only its instance variables, a1 and a2.

Finally we return to the result of MyClassB's init. There MyClassB will initialise its and only its instance variable, b.

Now we have an allocated and initialised MyClassB object.

hrishidev
Jun 17, 2011, 05:40 AM
Except that it is actually equivalent to a calloc, because I believe Apple's documentation says all ivars have and initial value of nil/zero/false.


I got little doubt here , if I use only alloc message without init method
and then use acessor methods to set instance variables , will it work like intialisation ?

I guess it would work , will check once I get back to my macbook

I know nobody writes code that way but just curious

jiminaus
Jun 17, 2011, 06:35 AM
I got little doubt here , if I use only alloc message without init method
and then use acessor methods to set instance variables , will it work like intialisation ?

I guess it would work , will check once I get back to my macbook

I know nobody writes code that way but just curious

I would work, assuming the assessor methods don't rely on the object's state to work correctly. There's nothing inherently necessary or special about the init family of methods. The purpose of initialisation is to get the object into an initial valid state. If all-zeros is valid initial state that I guess a call to init could be avoided.

But I wouldn't do this.

larswik
Jun 17, 2011, 03:15 PM
jiminaus - you would make a good teacher. Breaking it down this way is better helping me get it. I think I might be over thinking a lot of this and that is why it is slow to sink in.

Your Inherits example of isa,a1,a2 and b that all get alloc'd and init into one object I understand clearly now. So this line of code that is common [[myClassB alloc]init]; is just using myClassB to determine the size the memory block should be, and initialize it.

When you said: "When you call init on the MyClassB object, the first statement in MyClassB's init should be: self = [super init]". I think of that code as begin this
myClassB * myObjectB = [[myClassB alloc]init];
It would think that when I init myClassB object, then by default all the 'ancestor' classes would also have to init?

( I am thinking as I write here) I think your other line might have clicked and partly answered the self = super init above. You said: "When you call init on the MyClassB object". In this case I am not init an object from a class, but init an object from an object? which would mean the object it's self would have to init the super classes, I think.

-Lars

jiminaus
Jun 17, 2011, 07:05 PM
When you said: "When you call init on the MyClassB object, the first statement in MyClassB's init should be: self = [super init]". I think of that code as begin this
myClassB * myObjectB = [[myClassB alloc]init];
It would think that when I init myClassB object, then by default all the 'ancestor' classes would also have to init?

( I am thinking as I write here) I think your other line might have clicked and partly answered the self = super init above. You said: "When you call init on the MyClassB object". In this case I am not init an object from a class, but init an object from an object? which would mean the object it's self would have to init the super classes, I think.


I think you've got in the end. After you alloc you have an object, albeit an uninitialised one. Remember Cocoa has two-step creation; allocation and then initialisation.