10

I always see example code where in the viewDidLoad method, instead of saying, for example

someInstanceVar = [[Classname alloc] init];

they always go

Classname *tempVar = [[Classname alloc] init];
someInstanceVar = tempVar;
[tempVar release];

Why is this? Isn't it the exact same thing, just longer?

Marty
  • 5,926
  • 9
  • 53
  • 91
  • I have never seen such construct, in which example code did you find it ? Could you please be more specific. Are `var` and `tempVar` member variables ? – Michal Sep 27 '10 at 18:37
  • 2
    Not only do you never see it. It's wrong. You might see something similar with the middle line replaced by `self.someInstanceVar = tempVar;` – JeremyP Sep 28 '10 at 08:49

1 Answers1

12

The short answer: This pattern shows up all the time in iPhone code because it is considered the best way to create a new object and assign it to a member variable while still respecting all of the memory management rules and invoking the appropriate side effects (if any) while also avoiding the use of autorelease.

Details:

Your second example would create a zombie, since var is left holding a pointer to memory that has been released. A more likely usage case looks like this:

tempVar = [[Classname alloc] init];
self.propertyVar = tempVar;
[tempVar release];

Assuming that propertyVar is a declared as copy or retain property, this code hands off ownership of the new object to the class.

Update 1: The following code is equivalent, but not recommended* on iOS, which is probably why most iPhone programs use the first pattern instead.

self.propertyVar = [[[Classname alloc] init] autorelease];

* autorelease is discouraged on iOS because it can cause problems when overused. The easiest way to be sure you never overuse it is to never use it all, so you will quite often see iOS code that uses alloc/init and release, even when autorelease would be acceptable. This is a matter of coder preference.

Update 2: This pattern looks confusing at first because of the memory management that Cocoa performs automagically behind the scenes. The key to it all is the dot notation used to set the member variable. To help illustrate, consider that the following two lines of code are identical:

self.propertyVar = value;
[self setPropertyVar:value];

When you use the dot notation, Cocoa will invoke the property accessor for the indicated member variable. If that property has been defined as a copy or retain property (and that is the only way for this pattern to work without creating a zombie), then several very important things happen:

  1. Whatever value was previously stored in propertyVar is released
  2. The new value is retained or copied
  3. Any side effects (KVC/KVO notifications, for example) are automatically handled
Community
  • 1
  • 1
e.James
  • 116,942
  • 41
  • 177
  • 214
  • my bad, fixed the code example. Still don't get why they do this. – Marty Sep 27 '10 at 18:46
  • 3
    There is a key difference between `instanceVar = value` and `this.instanceVar = value`. Using the dot notation tells the compiler to invoke the property accessor, which takes care of the memory management automatically behind the scenes. – e.James Sep 27 '10 at 18:48
  • okay so the dot notation invokes the property accessor, and without the dot it just sets the instance variable?...I miss java... – Marty Sep 27 '10 at 18:55
  • Don't you usually use `self.[…]`? @marty: The `self.instanceVar` accesses a property set in the `.h`-file. This will also `retain` the new value of `instanceVar`. – Emil Sep 27 '10 at 19:01
  • @marty: Yes, that is correct `:)` It's a tricky concept at first, but if it bites you once you'll never forget. – e.James Sep 27 '10 at 19:02
  • @e.James @marty No, it's not entirely correct. You need the entire `self.`-part to actually access the property. – Emil Sep 27 '10 at 19:04
  • oh so since it's using the property accessor, it's retained. But I'm still not sure about the original problem. What's the difference between making a temp and just straight initializing the instance variable? – Marty Sep 27 '10 at 19:05
  • @marty: I added some more details to my answer, which I think may help explain. You *can* assign directly to the instance variable as in your very first example, but this leaves you open to errors down the road. One potential problem is that the old value in `instanceVar` is not released before the new one is assigned. Obviously that isn't a problem if there was no value in `instanceVar`, but rather than rely on that assumption, it is easier to always use the "alloc, set property, release" pattern and sleep easy. – e.James Sep 27 '10 at 19:13
  • You explained how assigning to properties is different, but not the reason why it's assigned to a temporary var before it's given to the property - why not simply this.propertyVar =[[SomeClass alloc] init]? – CiscoIPPhone Sep 27 '10 at 19:41
  • 1
    Good question. You have to use the intermediate variable so that you have something to release when you are finished. If you call 'self.propertyVar = [[Someclass alloc] init];', you can very easily leak the new object. Say, for example, that 'propertyVar' was a copy property. The property accessor would then dutifully copy that new object, and the *copy* would be properly released in your 'dealloc' method, but the original would simply be leaked. – e.James Sep 27 '10 at 20:48
  • My pleasure. I'm glad you brought up that last point. I've been doing this for so long, I sometimes forget to explain some of the details. – e.James Sep 27 '10 at 21:44
  • 2
    Surely you mean `self` rather than `this`? – Chuck Sep 27 '10 at 23:26
  • @Chuck: Argh. Yes, surely I do. Thank you for spotting that. – e.James Sep 27 '10 at 23:58
  • The advice to avoid usage of autorelease on iPhone is probably the most misunderstood pieces of advice on the Apple web site. In this case, for example, autoreleasing the newly created instance will likely have minimal impact, because it is probably supposed to survive the end of the current run loop event anyway. Avoiding autorelease is a case of premature optimisation and is thus partly the root of all evil. – JeremyP Sep 28 '10 at 08:58
  • @JeremyP: It's a tricky issue. Even in this example, autorelease would be perfectly harmless if this block of code was only called a couple of times. However, if the same block of code was called from within a loop, the effects could be quite severe. Since it is very difficult to guarantee that a particular block of code will not be called from within a loop, the easiest way to be safe is to avoid autorelease altogether. – e.James Sep 28 '10 at 09:13
  • @JeremyP: I wouldn't really call this an optimization issue. It's more like the use of `goto`: while it is certainly *possible* to use it without causing problems in your code, it is definitely safer *not* to use it at all. – e.James Sep 28 '10 at 09:17
  • @e.James: if, if, if... *profile* to find out the issues and optimise when you *know* there is a problem. In any case, wrapping each iteration of the loop in an autorelease pool might be a better answer than jumping through hoops to avoid autorelease. – JeremyP Sep 28 '10 at 09:19
  • @JeremyP: I agree that premature optimization should be avoided, but I don't see the `alloc/init`, assign, `release` pattern as an *optimization*. To me, it is more of a convenience and safety issue. If you always use this pattern, you never have to worry about the potential side effects of autorelease. – e.James Sep 28 '10 at 09:32
  • @e.James: not all optimisation is about speed. There is also optimisation for memory footprint. alloc/init and release are potentially more dangerous than autorelease in most situations since there is more potential for memory leaks. For instance, -stringWithFormat: gives you an autoreleased object that you can forget about after you have used it, but alloc/initWithFormat: requires you to assign a temp variable and release the temp variable later. The code is uglier and if you forget the release - memory leak. – JeremyP Sep 28 '10 at 09:39
  • @JeremyP: I'm familiar with the different types of optimization, and I can certainly see your side of this issue: autorelease is avoided in order to keep temporary memory usage down, which is a memory footprint optimization. If your app was the only one running on the device and you could easily profile for the majority of the usage cases, there would be little reason to avoid autorelease. – e.James Sep 28 '10 at 10:03
  • My take on this is that since the iPhone and other iDevices are memory-constrained, and you never know how much room you will have, the safest bet is to avoid autorelease. Apple's dev tools do a pretty good job of finding any memory leaks that you might introduce with temporary variables. – e.James Sep 28 '10 at 10:07