Advertise Mobile SDKs Books Events Forum News Social Networking Support Us
Follow @iphonedevsdk on Twitter

Mockup & CodeGen, iPhone & iPad
($9.99)

Make your own iPhone apps
and run them live!
(free)

Manu
($0.99)

Want your application or service advertised on iPhone Dev SDK?

Go Back   iPhone Dev SDK Forum

View Single Post
Old 12-02-2008, 04:09 PM   #2 (permalink)
rames44
Mobile Geek
 
Join Date: Aug 2008
Location: Florida, USA
Posts: 365
Send a message via AIM to rames44 Send a message via Yahoo to rames44
Default Getters, setters and properties for the newbie, Part II

So now we've simplified the process of writing our source code - we don't have to write those tedious getter and setter methods manually - the compiler can automagically generate them given the information that we've provided it.

That wasn't enough for the Objective C gurus, however. After a while, I guess they got tired of writing code like
Code:
    NSString *s = [obj text];
    [obj setText:@"new string"];
    int i = [obj value];
    [obj setValue:3];
As a result, along with the autogenerated code feature we just discussed, the property stuff introduced a new notation:
Code:
    NSString *s = obj.text
    obj.text = @"new string";
    int i = obj.value;
    obj.value = 3;
Basically, since the @property and @synthesize lines gave the compiler enough information to generate the getters and setters, it also gave it enough information to know how to call them. Thus, the four lines just above are absolutely functionally identical to the four lines of code just before that. Under the hood, the exact same thing happens - calls to getters and setters - you the programmers just get to write code that's a little more concise.

Now, this is where the slightly twisty bit comes in particularly for Java programmers. In Java, many people will write a function like this:
Code:
void doSomething(String text)
{
    this.text = text;
}
In this Java function, "text" is a local variable, while "this.text" is a member of the class that happens to have the same name. If you were to try to directly translate this into Objective C, you might come up with
Code:
-(void)doSomething:(NSString *)text
{
    self.text = text;
}
In this case, however, "self.text" is not a direct reference to the member variable "text" the way it is in Java. Instead, it is shorthand for a function call to the method
Code:
-(void)setText:(NSString *)text;
As a result, the two lines in this function have significantly different effects:
Code:
-(void)doSomething:(NSString *)input
{
    text = input;        //direct variable assignment
    self.text = input;  //call to the setter
}
It may not be obvious at first that these two lines have different results. Indeed, if we were dealing with an integer property that would, in fact, be the same. When we're dealing with a retained item like a string, however, the first line will overwrite the pointer to the string without releasing any previous value or retaining the new one while the second line will release the old value and retain the new one. Obviously a very different thing.

As a result of this, it is almost always better to use the "self.text =" form instead of the "text =" form - the latter is quite likely to generate memory leaks. To use the "text=" form properly, one would have to do:
Code:
-(void)doSomething:(NSString *)input
{
    [input retain];
    [text release];
    text = input;
}
in order to make sure that the memory was handled properly. But guess what? This is essentially identical to the setter that was automatically generated for us, so why not just do it as:
Code:
-(void)doSomething:(NSString *)input
{
    self.text = input;
}
and save the aggravation and potential for bugs.

Carrying this a bit further, this is why you see code that looks like this so often:
Code:
-(void)doSomething
{
    SomeObject *obj = [[SomeObject alloc] init];
    self.obj = obj;
    [obj release];
}
The first line creates an object. Since we "alloc'd and init'd" the object, it now has a retain count of one. Then we call the setter in the second line. The setter was presumably defined to retain the object, so that makes the retain count two. Then the third line releases the object once. This balances out the implicit retain in the first line, leaving the retain count at one, meaning that the only reference to the object is by the owner.

It is almost always best to code this way, because it helps you make sure that you're balancing out retains and releases, thus preventing memory leaks. The two fundamental rules are:
1) If you allocate it, create it or copy it, you need to release it.
2) If you retain it, you need to release it.

As far as rule #1 goes, it's easy to see that the "alloc" and "release" are balanced out when you write code like this.

As far as rule #2 goes, the "retain" that's automatically generated inside the setter is balanced out in one of two places:
a) By the generated "release" if the setter is called again, or
b) By the "release" that you wrote into your "dealloc" function.

Now, having said all that, there is one place in which writing "direct assignment" code, as opposed to "create/setter/release" code is perfectly fine, and that's inside an "init" function. Your "init" function is supposed to get called only once - immediately after an object has been allocated. As such, you know that all the member variables are "nil" (or zero). As such, you don't have to be paranoid about making sure that a previous value is released. Thus, in your init function, it's perfectly fine to write:
Code:
    obj = [[SomeObject alloc] init];
instead of
Code:
    SomeObject *obj = [[SomeObject alloc] init];
    self.obj = obj;
    [obj release];
Both sets of lines have the same effect - a member variable named "obj" is left holding an object with a release count of one. Thinking back to rule #2 above, the implicit "retain" caused by the "alloc/init" line is balanced out by the "release" we wrote into the "dealloc" function.

So what would happen if you wrote:
Code:
    self.obj = [[SomeObject alloc] init];
In this case, you're holding onto an object with a retain count of two - the first count comes from the "alloc" and the second one is added by the setter.

To release this variable, you'd have to do something like this:
Code:
    [obj release];
    self.obj = newValue;
so that "release" gets called twice on the object. If you omit the extra "release", then when the pointer gets overwritten the object will still be floating around with a retain count of one, and thus doesn't get deallocated. Instant memory leak.

Last edited by rames44; 12-02-2008 at 04:15 PM.
rames44 is offline   Reply With Quote
 

» Advertisements
» Online Users: 748
21 members and 727 guests
annchavez78, armmzz, at0m87, charleslazarev, Clouds, dfvdan, Domele, ghz.rai, gladlard24, Gurpartap Singh, HerbertMIbarra, Macaret, maghett004, Meoz, MSJJ, nidie, oztemel, phackdat, smethorst, socbaybot, soonw29
Most users ever online was 1,187, 10-11-2011 at 08:09 AM.
» Stats
Members: 158,822
Threads: 89,206
Posts: 380,634
Top Poster: BrianSlick (7,129)
Welcome to our newest member, gladlard24
Powered by vBadvanced CMPS v3.1.0

All times are GMT -5. The time now is 02:24 AM.
Powered by vBulletin® Version 3.8.0
Copyright ©2000 - 2012, Jelsoft Enterprises Ltd.