Register FAQ / Rules Forum Spy Search Today's Posts Mark Forums Read
Go Back   MacRumors Forums > Apple Systems and Services > Programming > iPhone/iPad Programming

Reply
 
Thread Tools Search this Thread Display Modes
Old Dec 30, 2012, 08:43 AM   #1
fstigre
macrumors regular
 
Join Date: Aug 2008
The use of the "self" keyword in Objective-C, see samples

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!
__________________
MacBook (not the pro version) 2.4 GHz - 4 GB RAM - 160 GB HD - Snow Leopard - iphone First Generation
- Mac mini - 1.6GHz First Generation with Leopard
fstigre is offline   0 Reply With Quote
Old Dec 30, 2012, 09:14 AM   #2
ArtOfWarfare
macrumors 603
 
ArtOfWarfare's Avatar
 
Join Date: Nov 2007
Send a message via Skype™ to ArtOfWarfare
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?
__________________
Don't tell me Macs don't last: 2007 iMac, 2007 Mac Mini, 2008 MacBook Air, all Vintage.
(iMac obsoletion: April 28, 2015, MBA: October 14, 2015, Mac Mini: March 9, 2016)

Last edited by ArtOfWarfare; Dec 30, 2012 at 09:27 AM.
ArtOfWarfare is offline   1 Reply With Quote
Old Dec 30, 2012, 01:35 PM   #3
fstigre
Thread Starter
macrumors regular
 
Join Date: Aug 2008
Quote:
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
Quote:
"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?

Quote:
ClassName *name = [[ClassName alloc]init];
Sorry, but may be I'm not at that level yet to understand your good explanation.

Thanks a lot.
__________________
MacBook (not the pro version) 2.4 GHz - 4 GB RAM - 160 GB HD - Snow Leopard - iphone First Generation
- Mac mini - 1.6GHz First Generation with Leopard
fstigre is offline   0 Reply With Quote
Old Dec 30, 2012, 03:40 PM   #4
firewood
macrumors 603
 
Join Date: Jul 2003
Location: 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.
firewood is offline   1 Reply With Quote
Old Dec 30, 2012, 05:56 PM   #5
Ides
macrumors member
 
Join Date: Mar 2012
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.
Ides is offline   1 Reply With Quote
Old Dec 31, 2012, 01:26 AM   #6
xStep
macrumors 68000
 
Join Date: Jan 2003
Location: Lost in Minneapolis
Quote:
Originally Posted by Ides View Post
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?

----------

Quote:
Originally Posted by fstigre View Post
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).
__________________
My App: CameraTime - Time lapse photography for novice and advanced users.
xStep is offline   0 Reply With Quote
Old Dec 31, 2012, 09:26 AM   #7
fstigre
Thread Starter
macrumors regular
 
Join Date: Aug 2008
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.
__________________
MacBook (not the pro version) 2.4 GHz - 4 GB RAM - 160 GB HD - Snow Leopard - iphone First Generation
- Mac mini - 1.6GHz First Generation with Leopard
fstigre is offline   0 Reply With Quote
Old Jan 1, 2013, 02:29 AM   #8
xStep
macrumors 68000
 
Join Date: Jan 2003
Location: Lost in Minneapolis
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; // <<-- We're overriding the getter as a lazy loading method.
- (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";    

     // Note: We're calling the model method in an instance of ViewController from another object, not self.
     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.
xStep is offline   1 Reply With Quote
Old Jan 1, 2013, 03:45 AM   #9
solderguy1
macrumors member
 
Join Date: Apr 2012
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 by solderguy1; Jan 1, 2013 at 02:27 PM.
solderguy1 is offline   1 Reply With Quote
Old Jan 1, 2013, 12:54 PM   #10
fstigre
Thread Starter
macrumors regular
 
Join Date: Aug 2008
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.
__________________
MacBook (not the pro version) 2.4 GHz - 4 GB RAM - 160 GB HD - Snow Leopard - iphone First Generation
- Mac mini - 1.6GHz First Generation with Leopard
fstigre is offline   0 Reply With Quote
Old Jan 8, 2013, 02:09 PM   #11
ctdonath
macrumors 65816
 
Join Date: Mar 2009
Quote:
Originally Posted by solderguy1 View Post
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.
ctdonath is offline   0 Reply With Quote
Old Jan 8, 2013, 03:17 PM   #12
ArtOfWarfare
macrumors 603
 
ArtOfWarfare's Avatar
 
Join Date: Nov 2007
Send a message via Skype™ to ArtOfWarfare
Quote:
Originally Posted by ctdonath View Post
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?
ArtOfWarfare is offline   0 Reply With Quote
Old Jan 8, 2013, 03:52 PM   #13
ctdonath
macrumors 65816
 
Join Date: Mar 2009
Quote:
Originally Posted by ArtOfWarfare View Post
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.
ctdonath is offline   0 Reply With Quote
Old Jan 11, 2013, 07:24 AM   #14
fstigre
Thread Starter
macrumors regular
 
Join Date: Aug 2008
Some more good info about the use of self.

http://stackoverflow.com/questions/9...in-objective-c
__________________
MacBook (not the pro version) 2.4 GHz - 4 GB RAM - 160 GB HD - Snow Leopard - iphone First Generation
- Mac mini - 1.6GHz First Generation with Leopard
fstigre is offline   0 Reply With Quote
Old Jan 11, 2013, 10:23 AM   #15
lastcall
macrumors member
 
Join Date: Jan 2013
Quote:
You need to use self to access variable in all places except:
-init
-dealloc
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:
Quote:
[self.variable release];
instead of
Quote:
[variable release];
lastcall is offline   0 Reply With Quote
Old Jan 11, 2013, 11:09 AM   #16
ChOas
macrumors regular
 
Join Date: Nov 2006
Location: The Netherlands
Quote:
Originally Posted by ArtOfWarfare View Post

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 by ChOas; Jan 11, 2013 at 12:17 PM.
ChOas is offline   0 Reply With Quote
Old Jan 11, 2013, 04:25 PM   #17
solderguy1
macrumors member
 
Join Date: Apr 2012
Quote:
Originally Posted by lastcall View Post
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.
solderguy1 is offline   0 Reply With Quote
Old Jan 11, 2013, 05:40 PM   #18
dejo
Moderator
 
dejo's Avatar
 
Join Date: Sep 2004
Location: The Centennial State
Quote:
Originally Posted by solderguy1 View Post
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];
__________________
dejo is offline   0 Reply With Quote
Old Jan 11, 2013, 10:32 PM   #19
lastcall
macrumors member
 
Join Date: Jan 2013
Quote:
Originally Posted by dejo View Post
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.
lastcall is offline   0 Reply With Quote

Reply
MacRumors Forums > Apple Systems and Services > Programming > iPhone/iPad Programming

Thread Tools Search this Thread
Search this Thread:

Advanced Search
Display Modes

Similar Threads
thread Thread Starter Forum Replies Last Post
2010 27" iMac screen issue..."dirty", "cloudy", image retention issues MMcCraryNJ iMac 1 May 18, 2013 04:02 PM
Objective alternates to 15" MBP quinn lebry MacBook Pro 6 Apr 10, 2013 09:31 AM
My Logic "track expander tube" doesn't have "end tips" to grab! Whats up? kristenanne77 Digital Audio 3 Mar 28, 2013 08:15 AM
Resolved: Weird problem with keyboard mapping : LMP Bluetooth Keypad's "enter" seen as "CMD" DanRom iMac 2 Aug 24, 2012 12:27 AM
Start a new tab similar to "iOS blog" and "Mac blog" but make it "IPhone Leaks?" Dewroo Site and Forum Feedback 2 Aug 23, 2012 09:47 AM

Forum Jump

All times are GMT -5. The time now is 05:38 PM.

Mac Rumors | Mac | iPhone | iPhone Game Reviews | iPhone Apps

Mobile Version | Fixed | Fluid | Fluid HD
Copyright 2002-2013, MacRumors.com, LLC