views:

181

answers:

4

I am using Core Data for my iPhone app. My attributes are set with retained properties.

For example, a "number" attribute in a "Thing" entity:

#import <CoreData/CoreData.h>

@interface Thing :  NSManagedObject  
{
}
@property (nonatomic, retain) NSNumber * number;
@end

@implementation Thing 
@dynamic number;
@end

When working with Thing objects in my code, I have been setting the number property like this:

thing.number = [[NSNumber alloc] initWithInteger:1];

However, this creates a memory leak (the new NSNumber object has a retain count that is one higher than desired due to the alloc plus property retain).

Since this is for the iPhone OS, I would like to manage memory myself, so I am choosing to not use autorelease pools (which also has the benefits of better performance and lower maximum memory usage).

  1. I know this pattern works (and it has been discussed in several SO posts already):

    NSNumber *num = [[NSNumber alloc] initWithInteger:1];
    thing.number = num;
    [num release];
    

    This pattern is very clear, but I am not thrilled about the three lines or temporary variable.

  2. I think that this will work as well (but I didn't notice it on any SO posts):

     thing.number = [[NSNumber alloc] initWithInteger:1];
     [thing.number release];
    

    This pattern is less clear, but only requires two lines and does not use a temporary variable.

Question
Are there any other patterns for assigning new objects to retained properties (without using autorelease pools)? What is the best practice here?

+1  A: 

Autorelease pools shouldn't use significantly more memory unless you're creating a lot of objects in a tight loop.

I guess your options are to either live with the 2 or three lines of code you need to write or to just use autorelease pools.

Personally, I'd definitely use autorelease pools unless I run into specific performance or memory problems.

Thomas Müller
My intention was to avoid turning this into a discussion of autorelease (which has been covered enough on SO in my opinion). I would agree that my application almost certainly would have no problem even with extensive use of autorelease objects for my Core Data attributes.
gerry3
+2  A: 

Whether you use them or not, autorelease pools already surround you code by default. Personally I don't think you would obtain much better performance if you don't use autoreleased objects. Keep in mind that autorelease pools and garbage collection are two different concepts, the former being much simpler. The only place where you wouldn't want to use autoreleased objects is in large loops.

For the record, the second pattern should work just fine too.

MihaiD
My intention was to avoid turning this into a discussion of autorelease (which has been covered enough on SO in my opinion). I would agree that my application almost certainly would have no problem even with extensive use of autorelease objects for my Core Data attributes. +1 for your consideration.
gerry3
+3  A: 

Aside from using autorelease pools, these are the only ones that I, for one, have seen. I wouldn't be too wary of autorelease. They work just fine, and this is a case where you'll probably not see any performance difference.

If you really want to avoid that, however, seems the applicable best practice here is the "Principle of Least Surprise". Since the first idiom is found in most of the example code out there, it seems like you should probably just suck up the extra line for the sake of whoever maintains the code.

Benjamin Cox
My intention was to avoid turning this into a discussion of autorelease (which has been covered enough on SO in my opinion). Good point about the "principle", but I will be maintaining this, so either method should work.
gerry3
+1  A: 

For many objects, you may use directly a method that returns an autoreleased instance. As an example, I usually write the equivalent of your code snippet as follows:

thing.number = [NSNumber numberWithInt:1];

Note that since your property is retaining the NSNumber, you will need to release it later, when you are done with the property.

Anyway, when this does not apply because you do not have constructors returning autoreleased objects, your pattern 1 is definitely correct.

Instead, pattern 2 seems to me incorrect for the following reason: you first assign the NSNumber to your property, then you release your property. However, you need to release the NSNumber you have allocated, not the one that was retained by your property (you will do this later,once again when you are done with the property). The net effect of pattern 2 should be a memory leak (the NSNumber allocated is not released) and your property not containing the NSNumber (because you first retained it and then released it).

unforgiven
For pattern 2, there is still only one object and its retain count is properly decremented. Remember: references (pointers) to objects do not have retain counts, objects have retain counts.
gerry3
Ok, this makes sense. Is there any Apple doc discussing this in more detail? Thank you in advance for sharing this.
unforgiven