Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

fstigre

macrumors regular
Original poster
Aug 12, 2008
158
1
Hi,

Can someone explain why the use of the "self" keyword when lazy instantiating?

Here I'm lazy instantiating a class called ModelClass, which requires to use of the "self" keyword when calling methods, why?
Code:
#import "ViewController.h"
#import "ModelClass.h"

@interface ViewController ()
@property (nonatomic, strong) ModelClass *model;
@end

@implementation ViewController
@synthesize model = _model;

-(ModelClass *) model
{
    if (!_model)
    {
        _model = [[ModelClass alloc]init];
    }
    return _model;
}


- (IBAction)showMessage:(id)sender
{
    NSString *word = @"This is a message";    
    self.display.text = [self.model message:word];    
}
@end


Here I'm directly instantiating class called ModelClass and does NOT require the "self" keyword.
Code:
#import "ViewController.h"
#import "ModelClass.h"

@interface ViewController ()

@end

@implementation ViewController
- (IBAction)showMessage:(id)sender
{
    NSString *word = @"This is a message";
    ModelClass *model = [[ModelClass alloc]init]; 
    self.display.text = [model message:word];    
}
@end


Can someone explain the use of the "self" keyword in general?

Thanks a lot for your help!
 

ArtOfWarfare

macrumors G3
Nov 26, 2007
9,560
6,059
Obj-C is just a thin veil that hides some ugly C code. This:

Code:
[target doSomethingWith:argument];
is equivalent to:

Code:
objc_msgSend(target, @selector(doSomethingWith:), argument);

In the case of when you're calling one of self's methods:

Code:
[self doSomethingWith:argument];
that's equivalent to:
Code:
objc_msgSend(self, @selector(doSomethingWith:), argument);

If you declare an instance variable in your header file, for example, you have:

Code:
@interface myClass : NSObject {
    int myInt
}

And then in your implementation file you have this:

Code:
- (void) setMyInt:(int)aInt {
    myInt = aInt;
}

That implementation is equivalent to this:
Code:
self->myInt = aInt;

Now... about your question, I'm a bit confused. None of your implemented methods that you've shared seem to be init methods. An init method should look something like this:

Code:
- (id) init {
    if ((self = [super init])) {
         // If [super init] returns NULL, this code won't execute.
         // This is the place to initialize your instance.
         // IE, you might have lines of code like this:
         [self prepareForRendering]; // Sure... why not?
         myInt = 42; // The default value.
         // And so on...
    }
    return self;
}

Now, why do you assign self? The answer:

An init method is allowed to return one of four things:
1 - The same instance it started with.
2 - A new instance of the same class that it started with.
3 - A new instance of some other class than what it started with.
4 - NULL.

1 is what you'd expect.
2 might be done if for some reason it's easier to start with a fresh new instance of your object.
3 is sometimes done for I don't honestly know why... a prime example is that calling init on an NSArray will instead return a CFArrayI or something like that... I forget what the exact class is... you'll see it sometimes in stack traces.
4 indicates that an error occurred. IE, you're completely out of memory.

I believe that a guarantee made for case 3 is that the instance returned will respond to all of the same methods and has all of the same instance variables as the original instance did, even though it may be of an unrelated class.

NULL consumes all calls to it, so trying to do stuff with NULL shouldn't actually be a huge issue... nonetheless, we generally skip playing with it and just return NULL (because at this point self is NULL) and someone else higher up can deal with it.

I just spent a few hours last night learning all of this... so I'm hoping I'm right about all of it... it's a confusing topic but I figure once I can teach it to someone else, it must mean that I've mastered it myself, right?
 
Last edited:

fstigre

macrumors regular
Original poster
Aug 12, 2008
158
1
Now... about your question, I'm a bit confused. None of your implemented methods that you've shared seem to be init methods. An init method should look something like this:

This code is similar to the one presented in the course from Standford University and to be quite honest I don't really understand your statement
"None of your implemented methods that you've shared seem to be init methods"
init methods?

I'm just instantiating a class, isn't this how you normally instantiate?

ClassName *name = [[ClassName alloc]init];

Sorry, but may be I'm not at that level yet to understand your good explanation.

Thanks a lot.
 

firewood

macrumors G3
Jul 29, 2003
8,108
1,345
Silicon Valley
In order to do lazy instantiation, you have to save the state of the object somewhere in order to know whether to instantiate it or not. Since you saved it in self, you can use the property getter to reference it.

Your second example doesn't save the model object anywhere. It just leaks it and re-instantiates another one if needed later.
 

Ides

macrumors member
Mar 27, 2012
95
0
If you use self.model then that is using a method to retrieve the object. self.model is the same as [self model]. You don't have to do it this way, but it's recommended for proper memory management.
 

xStep

macrumors 68020
Jan 28, 2003
2,031
143
Less lost in L.A.
If you use self.model then that is using a method to retrieve the object. self.model is the same as [self model]. You don't have to do it this way, but it's recommended for proper memory management.

How do you figure it's recommended for proper memory management?

----------

Hi,

Can someone explain why the use of the "self" keyword when lazy instantiating?

Can someone explain the use of the "self" keyword in general?


Each message is sent to a required receiver, an object id. To refer to a method within an instantiated object, that receiver id is `self', a hidden instance variable. This is the id generated when you created the object. The object knows about it self via the self id and any method calls made internally will need that id. So, in your first block of code, the only way to call the model method is to use self as the receiver. You're using the dot notation short cut.

See the Working with Objects section in Apple's Programming with Objective-C


In your second block of code you are creating a local variable based on ModelClass. The variable, model, is not an instance variable of ViewController with a supporting getter method and is instead an object and the receiver of the message: method.

To complicate matters, you could have a variable with the same name declared as an instance variable, as a local variable within a method, and even further localized variable within a block of code within method. You should also read about variable scope at
Objective-C Variable Scope and Storage Class and Scope (computer science).
 

fstigre

macrumors regular
Original poster
Aug 12, 2008
158
1
Thank you all for your replies.

If I'm understanding this correctly the main reason why we use the self keyword when calling methods from lazy instantiation objects, is because the self keyword was somehow assigned to it when the property was created (some internal id that can only be access through the self keyword), where in my second sample I'm only creating a variable holding the object.

I think I now have a better idea, I will read the links provided to understand this a little bit more.

Thanks a lot for your help.
 

xStep

macrumors 68020
Jan 28, 2003
2,031
143
Less lost in L.A.
fstigre, you are confusing things.

The use of self in your first block of code is used because you are making a local call within the object to a method within that object. It has nothing to do with lazy instantiation.

Your model method in the first block of code can be called from any object that knows about an instantiation of your ViewController class. So, you could have something like the following.

Code:
// Interface for ViewController
#import <UIKit/UIKit.h>
#import "ModelClass.h"
@interface ViewController : UIViewController
@property (nonatomic, strong) ModelClass *model;
- (ModelClass *) model; // [COLOR="red"]<<-- We're overriding the getter as a lazy loading method.[/COLOR]
- (IBAction)showMessage:(id)sender;
@end

<assume your implementation code here for ViewController. Nothing changed.>



// Interface for some other class.
#import <UIKit/UIKit.h>
#import "ViewController.h"
@interface MyOtherViewController : UIViewController
- (void) doSomething;
@end


// Implementation for some other class.
#import "MyOtherViewController.h"
@implementation MyOtherViewController
- (void) doSomething
{
     ViewController * yourViewController = [[ViewController alloc] initWithNibName:@"ViewController" bundle:nil];

     NSString * someOtherWords = @"This is a message from xStep";    

     //[COLOR="Red"] Note: We're calling the model method in an instance of ViewController from another object, not self.[/COLOR]
     NSString * someNewText = [yourViewController model] message: someOtherWords];    
     ...
    <do something with someNewText, and yourViewController>
}
@end


Extra: Note that in your model method you should NOT reference the model instance variable via self. That could cause an endless loop.



In your second block of code you are creating object of the Model class that is local in scope to the showMessage: method.
 

solderguy1

macrumors member
Apr 20, 2012
40
0
I'm going to take things down a notch in case anyone's not clear.

In Obj-C, objects are created from a class and accessed with a pointer reference. In the code below, myFoo and myBar are pointers to objects created from the Foo and Bar classes.

They are usually used to set instance variables (ivars) and invoke methods in other objects. While they can be used for ivars and methods within the same object, it's easier to use self. Self is just a pointer to the object which is currently running code, similar to "this" in other languages.

If your lazily-instantiated object was created within another object's method, you'd have to use the other object's pointer, not self.

In fact, you don't need to specify self when invoking an method in the same object. It's just a style, some programmers think it makes things clearer. Try it both ways with a test method and see.

If you synthesized a setter for an ivar myVar, the compiler will generate setter and getter methods for you. And you can invoke self.myVar which will run the setter method instead of changing myVar's value directly. This has three advantages:

1. If the ivar is an object pointer, the previous object pointed to will be sent a release message. This used to be important to prevent memory leaks, but it's now automatic if ARC is used. And it's a non-issue for primitive ivars.
2. You can write a custom setter method if you want it to run additional code, like incrementing a timesChanged counter or setting an isDirty flag.
3. Getters and Setters support Key Value Observing

Don't use self in these methods:
1. Init - the ivar is not fully created yet.
2. Dealloc - the ivar is on the edge of a cliff. ARC won't let you anyway
3. Custom setter - self will invoke the custom setter, so you'll get a recursive infinite loop


Code:
Foo *myFoo = [[Foo alloc] init];
Bar *myBar = [[Bar alloc] init];

[myFoo fooMethod];
[myBar barMethod];
[self  barMethod];   // if called from a method in the myBar object

myBar.barVar = 5.0f;  // can't remember if this is direct or setter, try with test case.
self.barVar = 6.0f;   // calling setter, must be currently in a method of the myBar object
barVar = 7.0f;  // setting directly from method in the myBar object

// will leak if already pointing at an object and no ARC
	workingPropertyString = [[NSMutableString string] retain];  
// will not leak
	self.workingPropertyString = [NSMutableString string];
 
Last edited:

fstigre

macrumors regular
Original poster
Aug 12, 2008
158
1
Thank you all for the good information, things are getting clear more and more.

I will try to digest all of the information as much as I can.

Thanks a lot for your help.
 

ctdonath

macrumors 68000
Mar 11, 2009
1,592
629
In Obj-C, objects are created from a class and accessed with a pointer reference.

Heh. I spent years in C++ trying to eradicate pointer use completely (references rule!), then switched to Objective-C and it's friggin' pointers everywhere.
 

ArtOfWarfare

macrumors G3
Nov 26, 2007
9,560
6,059
Heh. I spent years in C++ trying to eradicate pointer use completely (references rule!), then switched to Objective-C and it's friggin' pointers everywhere.

What's wrong with pointers? I understand they're a rather difficult concept to grasp, but once you get them, why not use them?

I'm not familiar with reference variables in C++ (I only first heard about them yesterday) but it doesn't seem to me that they're any less complicated, are they?
 

ctdonath

macrumors 68000
Mar 11, 2009
1,592
629
What's wrong with pointers?

Way, way too easy for pointers to go very, very wrong.

Rarely are you thinking in terms of pointing at where something is, you just want to refer to the thing by name - hence references. A symbolic name is applied at the outset, and you never have to worry about whether you're not referring to it; if you have the name you have the object, and if you don't have the name then, well, you can't screw things up. Construction and destruction sequencing becomes inherent based on usage. Sometimes it's a bit hard to use a reference, but most of the time that's a matter of design or understanding, not an inherent problem. Inability to use a reference is a good indication the architecture should be changed, that there's a better way.

Pointers, however, are all too often pointing to something other than what you want to point at. ("All too often" of course contingent more on the severity of error than frequency.) From the time the pointer is created to the time it is assigned a correct value, 'tis possible to use the pointer to access, well, whatever it's pointing at - and doing so by accident can be very hard to debug because the results are either very subtle ("where'd my data go? and why did this other unrelated variable change? oh...") or devastating (BSOD). Pointers can be changed unawares ("++p" vs "++*p", oops!). And worst of all, pointers continue to point at where data was but isn't anymore (get pointer to object, use object, delete object, creator of object proceeds to use and delete now non-existent object); less so but still too often you have to track who's responsibility it is to delete the object pointed to.

One of the most obnoxious things about pointers is NULL: the obsessive need to check whether a pointer is or not. (Remember, I'm addressing C++, where references are an option, not Objective-C where they're not and "nil" & automatic reference counting solves a lot of pointer problems.) Sure, safe pointer programming involves setting a pointer to NULL if it's not pointing at something...and now you have to always check for that special case and act thereon. Most of the time you don't check because "it will never be NULL here", but longtime programmers have learned sometimes it is. No such issue with references; if you have the name, you have the object.

Of course you can function perfectly well with pointers instead of references. It's that if you don't code perfectly well, pointers will bite you - and I've been bitten way too many times. References eliminate a number of subtle and serious problems, and encourage better programming by making it hard to do stuff prone to error. Proper use of references requires a change in thinking about accessing data, which is sometimes baffling but almost always ends up improving the code.

Alas, I'm back to pointers everywhere again. Good thing Objective-C can send messages to nil, and unreferenced objects are eradicated - solving the two biggest problems with pointers.
 

ChOas

macrumors regular
Nov 24, 2006
139
0
The Netherlands
3 - A new instance of some other class than what it started with.

3 is sometimes done for I don't honestly know why... a prime example is that calling init on an NSArray will instead return a CFArrayI or something like that... I forget what the exact class is... you'll see it sometimes in stack traces.

Maybe to shed some light (at least, this is why I personally use this sometimes)

It's called a Factory Object/Class.

I work a lot with network objects (I write spiders to collect data from a VERY big network)

What I do is this (pseudo):

Code:
node nodeToBeScanned = [[Node allocNodeFromName:<nodename>] init];
result = [nodeToBeScanned scanNode:<blah blah blah>]
[node storeScanData:result];

Or something like that.

Now, when I call Node allocNodeFromName: I pass the node name. The Factory looks up the type of node it is and returns an object based on the type (Router object, Switch object, Firewall object). All these objects have different init and scanNode: methods. But might share some methods which the Node class provides, Node returns something that is subclassed from itself.

So in my program I don't need to know what kind of thing I'm scanning, I'm just trusting the factory to pass me back an object based on the appropriate type (which the factory figures out for me).

See here: http://en.wikipedia.org/wiki/Factory_method_pattern
 
Last edited:

solderguy1

macrumors member
Apr 20, 2012
40
0
Is this true? I have seen many Objective-C example code use self in those methods.

The only time I see code crash is calling release, like:

instead of

I got those from the Stanford IOS lecture videos. Don't use self in:
init - not fully created yet
dealloc - it's on the edge of a cliff.

If I'm wrong, someone please correct me.
 

dejo

Moderator emeritus
Sep 2, 2004
15,982
452
The Centennial State
I got those from the Stanford IOS lecture videos. Don't use self in:
init - not fully created yet
dealloc - it's on the edge of a cliff.

If I'm wrong, someone please correct me.

I don't believe that's correct. You have to be careful how you use them in those methods (for the reasons given) but I've even seen Apple code that uses them in both, like so:

Code:
- (id)init
{
    self = [super init];
    if (self)
    {
        // Initialization code here.
    }
    return self;
}

Code:
- (void)dealloc
{
    self.propertyName = nil;
    [propertyName release];
    [super dealloc];
 

lastcall

macrumors member
Jan 10, 2013
51
6
I don't believe that's correct. You have to be careful how you use them in those methods (for the reasons given) but I've even seen Apple code that uses them in both, like so:

Code:
- (id)init
{
    self = [super init];
    if (self)
    {
        // Initialization code here.
    }
    return self;
}

Code:
- (void)dealloc
{
    self.propertyName = nil;
    [propertyName release];
    [super dealloc];

Thanks, that makes sense. Can't use self in init, until it is allocated.

I was thinking maybe XCode can give us a compiler warning if we use "self" in init and dealloc, but there are
special cases where we can use them safely, so that would be pointless.
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.