Retaining / releasing properties

Member
Posts: 61
Joined: 2009.01
Post: #1
Hey everyone.

I have a question about how retain behaves when using it with properties. Say my class is as follows:
Code:
@interface Foo : NSObject
{
@private
     MyObject *object;
}
@property (retain) MyObject *object;
@end

@implementation Foo
@synthesize object;
@end

Logic would denote (as well as reading that I've done), that this will cause a memory leak because I am not releasing object in Foo's dealloc method. However, I get a runtime error when I try to dealloc a retained property, as if it is automatically handled somehow.

So how exactly does this work? Should I be releasing my properties in dealloc or no?

Thanks very much.
Quote this message in a reply
Moderator
Posts: 133
Joined: 2008.05
Post: #2
Declaring something a property and then synthesizing it just writes the accessors for that instance variable. The property attributes tell the compiler how to write those accessors.

Yes, you do need to release them. What is the error you are getting? In fact, paste some code.
Quote this message in a reply
Nibbie
Posts: 2
Joined: 2009.01
Post: #3
If you're getting a runtime error on dealloc then it's possible that you're not using property notation to assign your MyObject instance.

In the land of Objective-C 2.0 properties, 'object' is not the same as 'self.object', Only the latter uses the property, and thus the synthesized setter/getter that does the automatic retention for you.

Check to see if you've got something like this in your code:

Code:
object = [MyObject objectConstructorConvenienceMethod];

If so you're bypassing the property setter and your instance of MyObject will not be retained. Change this to the following will fix this issue:

Code:
object = [MyObject objectConstructorConvenienceMethod];

Another possible cause might be if you're using a temporary variable to hold an object instance returned from a constructor convenience method and then releasing it afterwards. The rule of thumb with Objective-C is that you only need to release an object if you have explicitly retained it, or you created it (alloc) or copied it. Any object instance returned from a method will likely be autorelease. Something like this is unnecessary, but not uncommon:

Code:
// autoreleased object created from convenience method
MyObject *tempObject = [MyObject objectConstructorConvenienceMethod];

// assign through property, incrementing reference count to 1
self.object = tempObject;

// release object, decrementing reference count to 0
[tempObject release];

In this case either do away with the temporary variable altogether, or simply remove the release statement as it's totally unnecessary.

If all that checks out, you might want to make sure that any other class that retains/releases the MyObject instance in question is doing so symmetrically and follows the above rules.

Hope this helps.
Quote this message in a reply
Moderator
Posts: 133
Joined: 2008.05
Post: #4
Another reason not to use dot-notation.

And one little nitpick that could confuse people, your third example isn't exactly correct. An autoreleased object has a retain count of 1, its just marked for release. Retaining it would bump that retain count to 2, and then on the next cycle of the run loop it would be bumped down to 1 via the autorelease pool.
Quote this message in a reply
Member
Posts: 254
Joined: 2005.10
Post: #5
I believe if you set up a property to be retain, then re-assigning that property to a new value will release the old value so you don't have to worry about it. This allows you to release a property by assigning it to nil. You must be certain you are using the dot notation or the synthesized accessors ([self object] and [self setObject:val]).
Quote this message in a reply
Member
Posts: 61
Joined: 2009.01
Post: #6
Well, I think seeing as there appear to be so many special rules involved that I'm just going to make all my object properties (readonly) and then create a setProperty function, which seems to do the trick. I only put the retain in there because I was getting a compiler error if I didn't do something with the object properties, and seeing as retain seemed to fix it I put that in. Then I was getting errors on release, as I mentioned. It sounds like I wasn't saying self.object = foo, and was just saying object = foo.

Looking at my code:
Code:
@property (retain) LevelSpace *space;
@property (retain) PathData *parent;
@property unsigned int cost;

- (id) initPathData:(LevelSpace *)obj withCost:(unsigned int)cst withParent:(PathData *)rent
{
    if (self = [super init])
    {
        space = obj;
        cost = cst;
        parent = rent;
        return self;
    }
    return nil;
}

That indeed appears to be the case. So if in the constructor I use self.space = obj, things will work? If not I'll just throw a (readonly) in there and do the retains manually like normal.
Quote this message in a reply
Moderator
Posts: 133
Joined: 2008.05
Post: #7
So properties are there to just save you from the extra typing (and the errors that come with that).

They don't do a whole lot special. When you synthesize a property in the implementation, the ONLY thing it does is create two methods: - (id)varname and - (void)setVarname:(id)obj.

Let's say you have a property:
Code:
@property (readwrite, retain) id object;

The following two blocks of code are EXACTLY identical as far as the compiler is concerned.
Code:
@synthesize object;
Code:
- (id)object
{
    return object;
}
- (void)setObject:(id)obj
{
    [obj retain];
    [object release];
    object = obj;
}

Now let's say your property is defined as such:
Code:
@property (readwrite, assign) id object;

Synthesizing that property is EXACTLY the same as:
Code:
- (id)object
{
    return object;
}
- (void)setObject:(id)obj
{
    object = obj;
}

Now let's say your property is:
Code:
@property (readonly) id object;

Then your synthesize only creates the getter, no setter is created.
Code:
- (id)object
{
    return object;
}

Writing the setter yourself is just a waste of time. Understanding what you are doing is much more important, and will save you time in the future. Do yourself a huge favor, and forget that dot-notation exists. It's not specific to properties, it's just syntactic sugar for sending messages to objects in Objective-C 2.0. It is hideous, and it's the source of your confusion.

Now back to understanding your original question. The code you had written was simply assigning a pointer (one of your instance variables) to a place in memory that describes an instance of an object. When that object is dealloc'ed (because its retain count reaches 0 later on in run time), you have still have a pointer. That pointer points to where that object used to be. That memory is most likely written over by this point, so its not a valid object.

Because you sending a release message to essentially random memory, bad things were happening. Using your setter method (which is told to retain the incoming object) will fix that, because now your object has a "leash" on that object. Your dealloc method has to release it because it put a leash on it with the setter. Some other object could have retained and released it a million times, but because you retained it once with your setter, you need to release its claim on the object.
Quote this message in a reply
Moderator
Posts: 3,573
Joined: 2003.06
Post: #8
longjumper Wrote:Writing the setter yourself is just a waste of time. Understanding what you are doing is much more important, and will save you time in the future. Do yourself a huge favor, and forget that dot-notation exists. It's not specific to properties, it's just syntactic sugar for sending messages to objects in Objective-C 2.0. It is hideous, and it's the source of your confusion.

I agree, I don't use dot-notation at all. It's not needed. I wish they hadn't added it because I agree that it seems to add more confusion than help (as evidenced here in this thread).

I do use the accessor synthesis stuff once in a while, but as you pointed out, that has nothing to do with dot-notation, and is merely a time-saving feature.
Quote this message in a reply
⌘-R in Chief
Posts: 1,256
Joined: 2002.05
Post: #9
I use em. I really don't see how they're confusing. As you said, it's exactly the same as writing the code yourself, so it's not hard to understand, IMO.
Quote this message in a reply
Moderator
Posts: 133
Joined: 2008.05
Post: #10
Properties are not confusing. They are simplifying things.

Dot-notation, to someone who is just learning Objective-C, is confusing.

When I teach, I make a point to never teach the different ways of connecting an outlet or action in IB, only the control-click way of doing it. Otherwise, you have multiple ways of getting the same result, and you are more concentrated on the way of getting the result than what the result actually means.
Quote this message in a reply
⌘-R in Chief
Posts: 1,256
Joined: 2002.05
Post: #11
I improperly interpreted Jakes reply. My badness.
Quote this message in a reply
Moderator
Posts: 3,573
Joined: 2003.06
Post: #12
Sorry, I wish I could have worded that better. Blush
Quote this message in a reply
Member
Posts: 61
Joined: 2009.01
Post: #13
Thanks for all the pointers on that, guys. Makes sense to me now.

And personally I like dot notation... well sort of, anyway. As someone coming from Java, dot notation is what makes sense to me, but consistency also makes sense. Saying myObj.length = 5 looks to my eyes like I've got a public instance variable, which of course is a no-no. So it makes sense just to have my own getting and setter methods and avoid the dot notation altogether, for the sake of consistency.

Thanks again.
Quote this message in a reply
Post Reply 

Possibly Related Threads...
Thread: Author Replies: Views: Last Post
  Intellectual Properties and Iphone Game Dev Bersaelor 1 1,704 Jan 17, 2010 05:45 PM
Last Post: Najdorf
  Releasing an Update kendric 8 3,743 Apr 21, 2009 06:50 AM
Last Post: kendric
  question regarding releasing an object Gillissie 1 1,765 Mar 16, 2009 02:10 AM
Last Post: maximile