Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Acceptable ways to release a property

Assume there is a class with the following interface:

#import <Foundation/Foundation.h>

@interface MyClass : NSObject {

}
@property (nonatomic, retain) NSDate* myDate;

-(void)foo;

@end

and the following implementation:

#import "MyClass.h"


@implementation MyClass
@synthesize myDate = _myDate;

- (void)dealloc
{
    [_myDate release];
    [super dealloc];
}

-(void)foo
{
    NSDate* temp = [[NSDate alloc] init];
    self.myDate = temp;
    [temp release];
}

@end

1) In the function foo will releasing like this ensure that the retain count of the objects is properly maintained (i.e. no memory is leaked and no unnecessary releases are performed).

    NSDate* temp = [[NSDate alloc] init];
    self.myDate = temp;
    [temp release];

2) Same question as in 1) except applied to the following technique:

self.myDate = [[NSDate alloc] init];
[self.myDate release]

3) Same question as in 1) except applied to the following technique:

self.myDate = [[NSDate alloc] init] autorelease];

4) Same question as 1) but applied to the following technique:

self.myDate = [[NSDate alloc] init];
[_myDate release]

5) Same question as 1) but applied to the following technique:

[_myDate release];
_myDate = [[NSDate alloc] init];
like image 305
sashang Avatar asked Sep 28 '11 01:09

sashang


2 Answers

1) Just fine.

2) Possibly unsafe, and will trigger warnings in the latest LLVM static analyzer. This is because the object returned by the getter method may not be the same one you passed to the setter. (The setter may have made a copy, for example, or may have failed validation and set a nil instead.) This would mean you were leaking the original object and over-releasing the one the getter gave back to you.

3) Just fine; similar to 1 but the release will come when the current autorelease pool is drained instead of immediately.

4) Possibly unsafe, but will not trigger warnings that I've seen. The issue is similar to the one described in 2; the object in the ivar may not be the one you passed to the setter.

5) Safe, but will not use the setter method or notify any observers of the property.

In the case where the property is a retain type, and both the getter and setter are just the synthesized versions, all of the above examples will work. However, they don't all represent best practice, and may trigger analysis warnings. The goal should be that the -foo method works correctly regardless of how myDate is managing its memory. Some of your examples above don't do that.

If, for example, you decided to change the property to copy later, you should not be required to change any other code to make it work correctly. In cases 2 and 4, you would be required to change additional code because the foo method is assuming that the setter will always succeed and always set the original object.

like image 96
BJ Homer Avatar answered Sep 23 '22 00:09

BJ Homer


5) is a bug - it leaks the old instance as it doesn't get released but just reassigned.

1) is clean and the best way to go. 4) is ok but puts some burden on the memory system - the object might live longer than needed. 2) technically ok, but you shouldn't directly retain/release the property - that's what the syntactic sugar is for! 3) technically ok, but also bypasses the property and relies on implementation details.

2) and 3) are discouraged and ask for trouble in the future when some part of code changes.

Edit: New code doesn't leak in 5). It has the same downsides, though.

There's a reason why we got support for properties, and it does a great and consistent use. You should only consider bypassing them if your time profile gives very clear hints that this is a bottle neck (unlikely).

like image 42
Eiko Avatar answered Sep 27 '22 00:09

Eiko