5

Which is the best way to handle creating an object to live in a retained property? I've included several examples.

Assume the property is:

@property (nonatomic, retain) myProperty;
@synthesize myProperty = _myProperty;

Option 1:

self.myProperty = [[[MyClass alloc] init] autorelease];

Option 2:

self.myProperty = [[MyClass alloc] init];
[self.myProperty release];

Option 3:

_myProperty = [[MyClass alloc] init];

Option 4:

MyClass *property = [[MyClass alloc] init];
self.myProperty = property;
[property release];
Monolo
  • 18,205
  • 17
  • 69
  • 103
Errol
  • 662
  • 1
  • 6
  • 13
  • Option 5: [self.property = [[MyClass alloc] init] release]; From http://twitter.com/mikeash/statuses/32651143389642752 – 0xced Oct 21 '11 at 09:17

4 Answers4

5

If in initialization of the object which holds the variable:

1) no. it's bad form to call through accessors in partially constructed states (e.g. init, dealloc)

2) no. it's bad form to call through accessors in partially constructed states (e.g. init, dealloc)

3) correct.

Exception: If your ivars are not private and you are in the implementation of a subclass of the type which declared the property, then you must also check to see if the parent class initialized the property. it's best to make the properties private or otherwise not directly accessible to subclasses.

4) no. it's bad form to call through accessors in partially constructed states (e.g. init, dealloc)

When you're working with a fully constructed instance:

1) this is fine when readbaility is more important than keeping your heap sizes low.

2) bad. the object returned from the getter is not necessarily the object you assigned.

3) bad. may introduce a leak if _myProperty is not nil.

4) best

justin
  • 104,054
  • 14
  • 179
  • 226
4

Option 1: Acceptable... but you're wasting resources with autorelease. The reference gets added to a list of items that need to get released at the end of the run loop... your variable stays around until then even if it doesn't need to.. etc, etc. I believe this option is used frequently... but I also believe it's lazy and wasteful.

Option 2: Confusing. Nothing wrong with it, per-se, but I'd say it's bad form.

Option 3: Acceptable, but not ideal. What if there is a custom setter? Etc. I'd personally only use this form within a custom setter itself, or, possibly in a class initializer. Otherwise, you're missing out on some of the benefits of properties.

Option 4: Best.

Steve
  • 31,144
  • 19
  • 99
  • 122
  • Autorelease is damn fast. Unless you've profiled your code and autorelease is a problem, it's counterproductive to be worrying about it at this stage. – Lily Ballard Oct 20 '11 at 21:47
  • Looks like you edited your post to even more strongly discourage the autoreleasing option. Why? This is a perfect example of premature optimization. You're giving up code readability for the sake of avoiding an extremely fast operation. – Lily Ballard Oct 20 '11 at 21:53
  • @Kevin; Agreed - but if it were, say, a UIImage which may get released before the run loop finishes, it'd be a waste of memory. Also, when I moved down to plain C for a particular project, and couldn't use autorelease anymore, I found that I had become overly reliant on autorelease - and that most of the time I was relying on autorelease there were actually much more elegant solutions available. – Steve Oct 20 '11 at 21:53
  • If it's being stored in an ivar, it's highly unlikely to be thrown away before the autorelease pool is drained, so it's not a memory saver. As for dropping down to C, I'm not sure what you're trying to say. C isn't object-oriented and doesn't have reference-counting semantics, and it doesn't even have a "native" runloop, so autorelease doesn't make sense. – Lily Ballard Oct 20 '11 at 22:01
  • @Kevin; Not true... if you're manipulating a bunch of images, and you're using autorelease on each of them, they'll stay around until the end of the run loop and potentially crash an iOS app. Whether or not they are temporarily stored in an ivar has nothing to do with anything. In regards to C; There are tons of C libraries which implement some sort of reference counting scheme. It's unavoidable in many situations... and you're right - it doesn't have a native run loop - so you have to find alternatives to autorelease - and most of the time you find something even nicer. – Steve Oct 20 '11 at 22:05
  • We're not talking about having a bunch of temporary images. We're talking about storing an object in an ivar. – Lily Ballard Oct 20 '11 at 22:13
  • @Kevin Ballard No - execution in autorelease contexts with many operations becomes very slow. When optimizing an app, removing unnecessary autoreleasing helps significantly (unless the noise of other problems is also very high). The problem is not "adding an object to a pool is slow". Yes, pool operations do complicate/worsen the issue... but it is the heap's state that is more significant in nontrivial programs. This is an example of a problem that you would not normally see in a sample, unless you know what to look for. – justin Oct 20 '11 at 22:58
4
self.myProperty = [[MyClass alloc] init];

Use ARC to generate your releases and retains at compile time.

followben
  • 9,067
  • 4
  • 40
  • 42
  • 1
    Ha ha... you stole my comment : ) I'm loving ARC by the way. – Steve Oct 20 '11 at 22:06
  • @Steve Shameless, I know :) I recommend it because it's obviously Apple's way forward. That said, I've a love/ hate relationship with ARC. I love the fact it inserts all MM calls for me, and makes my code faster and less bug-ridden. I hate that my head hurts trying to figure out _what_ it's going to insert. I just spent years internalising retain cycles and now I've gotta forget all about them and think in object graphs. :-S – followben Oct 20 '11 at 22:20
  • I'll definitely look into ARC but I'm still new to Cocoa and want to learn the "right" ways :-) before the fancy new ways. – Errol Oct 21 '11 at 14:42
  • @Errol Actually, unless you need to target iOS 4 or below, I'd highly recommend going with ARC from the get-go. As I said in my comment above: ARC requires you to think a little differently than release/ retain. Indeed, as it applies release/ retain calls in a slightly different fashion to how you'd code them by hand, you might find knowing the old "right" way actually holds you back from adopting the new right way. At least it did me... – followben Oct 21 '11 at 20:57
  • I do need to target iOS 4 for a while, but also may come across legacy code I'd have to maintain as well. – Errol Oct 21 '11 at 23:22
2

Option 1 is correct.

Option 2 is absolutely wrong. You never call -release on the results of a property accessor.

Option 3 is avoiding properties entirely. This is actually correct in your -init method, but in other methods it's better to use the property setter unless you have a good reason to avoid it.

Option 4 is correct as well, though it's more verbose than option 1. Your call.

Edit: I misread your option 4 originally.

Lily Ballard
  • 182,031
  • 33
  • 381
  • 347