2

Possible Duplicate:
Incorrect decrement of the reference count of an object that is not owned at this point by the caller
Why shouldn't I use the getter to release a property in objective-c?

So, I get that using [self.myProperty release] is discouraged (Apple itself recommends not to). Although it appears to me that it COULD lead to problems in some cases, not all cases. Is this correct? More importantly: I don't get why using a syntax like [self.myProperty release] in my -dealloc method(s) will cause the static analyzer to show an "incorrect decrement" error. Despite any other reason discouraging such a syntax, my class still owns its properties (which I have declared with "nonatomic,retain") so why the warning?

I've been reading several posts on this but it seems I can't really wrap my mind around it. Some of them go into details about the possible side effects of using such a syntax, but what I really want to know is the reason behind the "incorrect decrement" error.

Any help would greatly be appreciated.

Community
  • 1
  • 1
CCSwift
  • 37
  • 5

3 Answers3

4

Cocoa memory management has a concept of "ownership" which is expressed most succinctly in the rule: If you call new or alloc, or send retain or copy to an object, you own the result, and are responsible for sending release when you're done with it. Otherwise, you do not own it, and you must not send release.

Instance variables, basically by definition, contain objects that the instance owns. You need the objects to be valid for the life of the instance, so you create them with an ownership-granting method in init:

// myDinkus and creationDate are ivars of whatever class this is.
// They are assigned to with owned references.
myDinkus = [[Dinkus alloc] init];    // ownership due to alloc
creationDate = [[NSDate date] retain];    // ownership due to retain

These now need to be sent release when the instance is done with them; generally speaking, this will be in dealloc.

Getter methods don't return owning references. This is the way it should be; when your code, e.g., asks a label for its font color, it doesn't need that color object to stick around. Or if it does, it must explicitly take ownership by sending retain. Giving it ownership by default would create headaches at best and possibly leaks.

That established, [self.myProperty release] causes the static analyzer to complain because it's a violation of the ownership concept. The object returned from [self myProperty] isn't owned by the caller. The fact that it just so happens to be the same object as an ivar that is owned by the caller is irrelevant. (In fact, it might not be the same; the getter might return a copy of the object it represents, for example. It might construct an entirely new value based on a group of ivars. It's even possible for there to be no ivar that corresponds to a getter.)

Since objects which are not owned must not be sent release, doing so to the result of a getter is incorrect.

There are other, practical, reasons not to do this (covered quite well, especially by Justin's answer in the question proposed as dupe), but that's the reason the analyzer is complaining.

Community
  • 1
  • 1
jscs
  • 63,694
  • 13
  • 151
  • 195
  • A key point here is that the getter is not required to simply return the underlying instance variable. I would suggest bolding that or something, since that's a clear and simple example of where the code could fail. Excellent response, though. – BJ Homer Jan 25 '12 at 19:42
  • @BJ: The answers at the linked question seemed to me to address the practical side. Given the OP's emphasis on just understanding the static analyzer's message, I wanted to focus on the rule. – jscs Jan 26 '12 at 06:53
  • @Josh: thank you SO much. I think the key here is "Getter methods don't return owning references." This is really what I was missing, trivial as it might be. Now it all adds up. – CCSwift Jan 26 '12 at 13:39
  • @BJ: You're exactely right, my emphasis was on the static analyzer's message, thanks for pointing that out. – CCSwift Jan 26 '12 at 13:48
1

Fundamentally, you're sending a release message to an object that you haven't sent a retain to (at least not explicitly). The static analyzer will expect to see balanced retain/releases.

paulbailey
  • 5,328
  • 22
  • 35
  • Wait, I don't get it. If that's true, then why is it OK with me just using `[myProperty release]`? – CCSwift Jan 25 '12 at 16:21
  • @user930765: At some point prior to the `dealloc`, you would've sent `myProperty` a `retain` message. – mipadi Jan 25 '12 at 16:37
  • @user930765: You probably don't get a compiler warning with `[myProperty release]` as you are not accessing the retained *property* but the underlying *instance variable* so they compiler is not giving you a property-related warning. However it is still the **wrong** way to do it - by specifying retain on your property you're asking for it to be handled for you, do not do it yourself, use `self.myProperty = nil`. – CRD Jan 25 '12 at 18:58
1

When you declare your property as nonatomic,retain you are handing responsibility for releasing the value to the property's setter.

If you do a [self.myProperty release] then your property still contains its old value and any subsequent setting of that property will do a release on that old value - but you've already released it, so now it is over-released... Hence the warning.

To release the value you should use self.myProperty = nil - the setter will release the old value and assign nil to the property.

CRD
  • 52,522
  • 5
  • 70
  • 86
  • The property setter would come into play if I was assigning a new value to the property, which I'm not.As I said, I tried using `[self.myProperty release]` in my `-dealloc` method. I'm only sending a `-release` message to the `self.myProperty`, which has been retained because of the way I declared the property itself. So what is wrong with this? – CCSwift Jan 25 '12 at 16:20
  • 1
    The compiler gives you a warning because it has no idea there will never be another call to the setter, and while you "know" a code change could alter that. By using `self.myProperty = nil` in your `dealloc` you avoid the issue and write robust code. – CRD Jan 25 '12 at 17:06