Advertise here




Advertise here

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Getters, setters and properties for the newbie

2»

Replies

  • khaleel8039khaleel8039 Posts: 3New Users Noob
    edited November 2010
    its a great tutorial for beginners....... keep it up .waiting for more from you bye
  • themknthemkn Posts: 29Registered Users
    edited January 2011
    Thank you very much for the tutorial. But there is something I don't understand. What is the difference between doing
        [textValue retain];
        [text release];
        text = textValue;
    

    and
        [text release];
        [textValue retain];
        text = textValue;
    
    The first one should be the correct one. But I don't see (logically) the difference. If you do first retain on textValue and then you release the variable text, can't it be that when you do text=textValue that the variable text is already deallocated (like the second one)?
  • rames44rames44 Posts: 365Tutorial Authors, Registered Users @ @
    edited January 2011
    themkn wrote: »
    Thank you very much for the tutorial. But there is something I don't understand. What is the difference between doing
        [textValue retain];
        [text release];
        text = textValue;
    

    and
        [text release];
        [textValue retain];
        text = textValue;
    
    The first one should be the correct one. But I don't see (logically) the difference. If you do first retain on textValue and then you release the variable text, can't it be that when you do text=textValue that the variable text is already deallocated (like the second one)?

    Remember that the special situation we're discussing is when "text" and "textValue" point to the same object.

    Suppose that we were the only one holding onto the object that "text" and "textValue" addresses. Thus, the reference count on that object is 1. In the first case, the "retain" increments the reference count to 2, the "release" decrements it to 1. The reference count never reaches zero, so the system doesn't deallocate the object.

    In the latter case, the "release" decrements the reference count to 0, and then the retain tries to increment it to 1. Sounds the same, however, as soon as the reference count hits zero, the system deallocates the object. Deallocations aren't somehow "deferred until later" - they happen as soon as zero is hit. So, perhaps much later, you then try to access the value addressed by "text," and you get an exception. It's a hard-to-find bug.

    If "text" and "textValue" point to different objects, then of course the "release" could cause the object addressed by "text" to be deallocated - that's entirely good and proper, and exactly what we want - in that case, the order doesn't really matter. It's only in this special "both point to the same object" case that the second order presents a problem - basically, it's a subtle bug. It isn't horribly likely to be triggered, since takes (effectively) something like:
       self.xyz = self.xyz;
    
    to trigger it, but it can happen if you do something like
       self.xyz = [self doSomeOperationAndReturnAResult];
    
    and there's some path where "doSomeOperationAndReturnAResult" could conceivably return "xyz".
    For a little fun, check out my <a href="http://itunes.apple.com/WebObjects/MZStore.woa/wa/viewSoftware?id=298866985&mt=8"; target="_blank">Biorhythms</a> app
  • themknthemkn Posts: 29Registered Users
    edited January 2011
    Ah I missed the point that both variables are pointing to the same object :). Thanks for your nice tutorial
  • ofirbtofirbt Posts: 9New Users
    edited March 2011
    The best post I've ever seen.
  • dougjackdougjack Posts: 1New Users
    edited May 2011
    Thank you for the incredibly clear and well-written post. After hours of searching on the web, this was a very welcome discovery.
  • CouicouiCouicoui Posts: 1New Users
    edited May 2011
    Hi there,
    First of all i want to join the round of applause for this clear and hour saving post. I still have one question about memory management that this post raise :
    But you also can't do
    - (MyObject *)getObject
    {
        return [[MyObject alloc] init];
    }
    
    because you've broken rule # 1 - you allocated it, but you didn't release it. What you really need to be able to do is tell Objective C "I'm responsible for this object, so I want to release it, but I want the release to be delayed until whoever asked for this object has had a chance to use it."

    I understand the issue, but suppose the calling function of getObject will be in charge of releasing the object, would that be an issue?

    For example :
    // The getter function
    - (MyObject *)getObject
    {
        return [[MyObject alloc] init];
    }
    
    // The caller function
    - (void)doSomething
    {
         MyObject *obj = [self getObject];
         
         // Do something with obj
    
         [obj release];
    
    }
    

    In that case we wouldnt have to use auto release, and we would know exactly when we release it. It might be a twisted way of programming, but id like to know if its a "clean" way of dealing with the issue, on a theoretical point of view.

    Thanks a lot!
  • manosfmanosf Posts: 1New Users
    edited June 2011
    Now, this was accurate, helpful, concise and thorough. Thank you very much for sharing this. It helped me clarify things and from what I've read, lots of other people too.
    I wish you the best in all your endeavors.
  • rames44rames44 Posts: 365Tutorial Authors, Registered Users @ @
    edited June 2011
    Couicoui wrote: »
    Hi there,
    First of all i want to join the round of applause for this clear and hour saving post. I still have one question about memory management that this post raise :



    I understand the issue, but suppose the calling function of getObject will be in charge of releasing the object, would that be an issue?

    For example :
    // The getter function
    - (MyObject *)getObject
    {
        return [[MyObject alloc] init];
    }
    
    // The caller function
    - (void)doSomething
    {
         MyObject *obj = [self getObject];
         
         // Do something with obj
    
         [obj release];
    
    }
    

    In that case we wouldnt have to use auto release, and we would know exactly when we release it. It might be a twisted way of programming, but id like to know if its a "clean" way of dealing with the issue, on a theoretical point of view.

    Thanks a lot!

    Typically, you try not to create these kinds of special situations, because it's hard to remember the responsibilities. Joe Programmer who comes along after you is unlikely to realize that he has to release the object, because he's been so indoctrinated into The Three Rules.

    If a callee creates an object, the autorelease pattern works just fine, of course - have the callee autorelease, and the object sticks around for the caller to use it and gets released later. The only "down side" to it is that the object may stick around longer than you like. If you were doing this inside a loop, for example, all the objects build up in the autorelease pool until you finally return from the message processing.

    Situations where you should (or have to) use autoreleased objects and where you want to force those objects to get released on command are an application for your own autorelease pool.
    - (void)doSomething
    {
        for (int i = 0; i &lt; 100000; i++)
        {
            NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    
            MyObject *obj = [self getAutoreleasedObject];
         
            // Do something with obj
    
            [pool drain];  // obj will be released here
            [pool release];
        }
    }
    

    In this case, the autoreleased objects get put into the autorelease pool we created, since it's the most "deeply nested" one. (There's still another one wrapping your message processing, but you can't get to that one.) When the pool is drained, all the objects that have built up inside it get released. Thus, this would release MyObject, plus any other autoreleased objects that might have been created during the call to getAutoreleasedObject.

    In this situation, without the autorelease pool, you'd build up 100,000 instances of MyObject in the surrounding autorelease pool until you returned and it got drained. Here, you clean up after yourself on each iteration of the loop.

    (Needless to say, you probably shouldn't be doing this kind of thing in a UI thread, but there are worker thread situations that resemble this.)
    For a little fun, check out my <a href="http://itunes.apple.com/WebObjects/MZStore.woa/wa/viewSoftware?id=298866985&mt=8"; target="_blank">Biorhythms</a> app
  • tofeeqtofeeq Posts: 2New Users
    edited July 2011
    Thanks for this important information which helped me much.

    I have some points that I didn't understand:

    the automatic setter method is:
    -(void) setText:(NSString *)textValue
    {
        [textValue retain];
        [text release];
        text = textValue;
    }
    

    let's take example
    NSString *text;
    @property (nonatomic, retain) NSString *text;
    @syn...
    
    ----
       
    view DId load:
        self.text = @&quot;hi&quot;;
    
    

    now the line in view did load will call the setter,
    first line in setter [textValue retain]; will increase retain to 1
    second [text release]; will decrease it to 0
    now we got no retain count??
  • rames44rames44 Posts: 365Tutorial Authors, Registered Users @ @
    edited July 2011
    tofeeq wrote: »
    Thanks for this important information which helped me much.

    I have some points that I didn't understand:

    the automatic setter method is:
    -(void) setText:(NSString *)textValue
    {
        [textValue retain];
        [text release];
        text = textValue;
    }
    

    let's take example
    NSString *text;
    @property (nonatomic, retain) NSString *text;
    @syn...
    
    ----
       
    view DId load:
        self.text = @&quot;hi&quot;;
    
    

    now the line in view did load will call the setter,
    first line in setter [textValue retain]; will increase retain to 1
    second [text release]; will decrease it to 0
    now we got no retain count??

    If "textValue" and "text" refer to different objects, then [textValue retain] and [text release] obviously deal with different retain counts.

    If "textValue" and "text" refer to the same object, then (since the object exists at the moment) its retain count must be non-zero before this code is executed. Thus, retaining it and then releasing it won't alter the retain count - it can't go to zero unless it was zero originally, and it can't be zero originally or it wouldn't exist.
    For a little fun, check out my <a href="http://itunes.apple.com/WebObjects/MZStore.woa/wa/viewSoftware?id=298866985&mt=8"; target="_blank">Biorhythms</a> app
  • tofeeqtofeeq Posts: 2New Users
    edited July 2011
    rames44 wrote: »
    If "textValue" and "text" refer to different objects, then [textValue retain] and [text release] obviously deal with different retain counts.

    If "textValue" and "text" refer to the same object, then (since the object exists at the moment) its retain count must be non-zero before this code is executed. Thus, retaining it and then releasing it won't alter the retain count - it can't go to zero unless it was zero originally, and it can't be zero originally or it wouldn't exist.


    Thanks for your replay.
    So, is my code for declaring a string and giving it an initial value is correct?
  • rames44rames44 Posts: 365Tutorial Authors, Registered Users @ @
    edited July 2011
    tofeeq wrote: »
    Thanks for your replay.
    So, is my code for declaring a string and giving it an initial value is correct?

    If you're talking about
    .h file:
    NSString *text;
    @property (nonatomic, retain) NSString *text;
    
    .m file
    @synthesize text;
    
    ----
       
    viewDidLoad:
        self.text = @&quot;hi&quot;;
    

    then yes, this is quite correct. The "property" declaration indicates that your class will retain the string, and the "synthesize" will automatically create the appropriate code to do just that.
        self.text = @&quot;hi&quot;;
    
    will then call the synthesized "setter", causing the member variable to be set with a retained version of the string, releasing any prior contents.

    You should also have a
      [text release];
    
    in your class's "dealloc" method in order to ensure that whatever string is assigned to "text" is properly released when your class instance is deallocated. If you don't do that, you will have a potential memory leak.
    For a little fun, check out my <a href="http://itunes.apple.com/WebObjects/MZStore.woa/wa/viewSoftware?id=298866985&mt=8"; target="_blank">Biorhythms</a> app
  • Caberry15Caberry15 Posts: 1New Users
    edited August 2011
    I am trying to do a similar quiz app and wanted to put images to questions. For instance if its a sports question I would put a sports picture, music question pic of guitar, etc.
  • applegalapplegal Posts: 1New Users
    edited September 2011
    Thank you for the excellent tutorial ! It really helped clear up a few things for me. :)
  • ExcelciusExcelcius Posts: 68New Users @
    edited September 2011
    Great post clear concise and thorough, Im currently busy swearing at several iPhone development books ;) I wish you'd write a one !

    I understood most of your posts but Im a little confused by the following
    rames44 wrote: »
    -(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.

    Why release obj surely the retained setter self.obj = obj, both releases and retains the pointer so the retain count remains at 1 not 2 and the final statement would reduce the retain count to 0 ?

    Thanks :)
  • rames44rames44 Posts: 365Tutorial Authors, Registered Users @ @
    edited September 2011
    Excelcius wrote: »
    Great post clear concise and thorough, Im currently busy swearing at several iPhone development books ;) I wish you'd write a one !

    I understood most of your posts but Im a little confused by the following



    Why release obj surely the retained setter self.obj = obj, both releases and retains the pointer so the retain count remains at 1 not 2 and the final statement would reduce the retain count to 0 ?

    Thanks :)

    self.obj = obj will release the OLD pointer (the previous "self.obj") and then will retain the one being set. The idea is that it disposes of the object that was previously being held, then retains the new one.
    For a little fun, check out my <a href="http://itunes.apple.com/WebObjects/MZStore.woa/wa/viewSoftware?id=298866985&mt=8"; target="_blank">Biorhythms</a> app
  • ExcelciusExcelcius Posts: 68New Users @
    edited September 2011
    rames44 wrote: »
    self.obj = obj will release the OLD pointer (the previous "self.obj") and then will retain the one being set. The idea is that it disposes of the object that was previously being held, then retains the new one.

    Yes I understand that, as in this example from your tutorial
    -(void) setText:(NSString *)textValue
    {
        [textValue retain];
        [text release];
        text = textValue;
    }
    

    but what I mean is, surely if the obj setter is similar to the above code, then wouldn't the following code produce these results
    -(void)doSomething
    {
        SomeObject *obj = [[SomeObject alloc] init];   //retain count = 1
        self.obj = obj;                        //retain count = 1 (not 2)
        [obj release];                        //retain count = 0 (not 1)
    }
    

    just to clarify my rather confusing question heres your post
    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.
  • rames44rames44 Posts: 365Tutorial Authors, Registered Users @ @
    edited September 2011
    Excelcius wrote: »
    Yes I understand that, as in this example from your tutorial
    -(void) setText:(NSString *)textValue
    {
        [textValue retain];
        [text release];
        text = textValue;
    }
    

    but what I mean is, surely if the obj setter is similar to the above code, then wouldn't the following code produce these results
    -(void)doSomething
    {
        SomeObject *obj = [[SomeObject alloc] init];   //retain count = 1
        self.obj = obj;                        //retain count = 1 (not 2)
        [obj release];                        //retain count = 0 (not 1)
    }
    

    Let's walk through it line by line, expanding into the subroutine.
    SomeObject *obj = [[SomeObject alloc] init];
    
    At this point, "obj" has been created and has a retain count of 1.

    When "self.obj = obj" gets executed, this results in:
    [textValue retain];
    
    At this point, "textValue" (the parameter to the subroutine) refers to the same object as "obj", so "obj" now has a retain count of 2.
     [text release];
    
    "text" does NOT refer to "obj" - it refers to whatever object was *previously* attached to the parent object. Thus, this decrements the retain count on the previous object, possibly releasing it, but does not alter obj's retain count.
    text = textValue;
    
    No alterations to the retain count.

    Now we're back out of the subroutine
    [obj release];
    
    "obj" has its retain count decremented from 2 to 1.

    Basically, "obj" starts with a retain count of 1 (from the alloc), and then has its retain count incremented when it is "attached" to "self". The retain count is then decremented with the explicit release. If I then did
    self.obj = anotherObj
    
    at that point, the "text" item inside the subroutine WOULD be referring to "obj" (since IT would now be the "old" object) and it would be released, decrementing its retain count to zero and causing the memory to be dealloc'd.
    For a little fun, check out my <a href="http://itunes.apple.com/WebObjects/MZStore.woa/wa/viewSoftware?id=298866985&mt=8"; target="_blank">Biorhythms</a> app
  • JumanjiJumanji Posts: 1New Users
    edited February 2012
    rames44 wrote: »
    Let's walk through it line by line, expanding into the subroutine.
    SomeObject *obj = [[SomeObject alloc] init];
    
    At this point, "obj" has been created and has a retain count of 1.

    When "self.obj = obj" gets executed, this results in:
    [textValue retain];
    
    At this point, "textValue" (the parameter to the subroutine) refers to the same object as "obj", so "obj" now has a retain count of 2.
     [text release];
    
    "text" does NOT refer to "obj" - it refers to whatever object was *previously* attached to the parent object. Thus, this decrements the retain count on the previous object, possibly releasing it, but does not alter obj's retain count.
    text = textValue;
    
    No alterations to the retain count.

    Now we're back out of the subroutine
    [obj release];
    
    "obj" has its retain count decremented from 2 to 1.

    Basically, "obj" starts with a retain count of 1 (from the alloc), and then has its retain count incremented when it is "attached" to "self". The retain count is then decremented with the explicit release. If I then did
    self.obj = anotherObj
    
    at that point, the "text" item inside the subroutine WOULD be referring to "obj" (since IT would now be the "old" object) and it would be released, decrementing its retain count to zero and causing the memory to be dealloc'd.

    just to say thanks nice tuts!!!
2»
Sign In or Register to comment.