Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In Objective-C, the ownership is for object, not variable or pointers?

Tags:

objective-c

In a book, the following is said:

So how do you know when an object is owned, and by whom? Consider the following example:

NSString *str = [[NSString alloc] initWithString:@”Hello”];  
NSString *str2 = str;

In this example, you use the alloc keyword for str, so you own str. Therefore, you need to release it when it’s no longer needed. However, str2 is simply pointing to str, so you do not own str2, meaning you need not release str2 when you are done using it.

I thought ownership is by object, not variable or pointer... so we can't say we "own str" or "own str2"... we own an object, which is pointed to by either str or str2, and if we use [str release] or [str2 release], it is all the same.

The other description is:

For example, consider the example used in the previous section:

NSString *str = [[NSString alloc] initWithString:@”Hello”]; 
NSString *str2 = str;
[str release];
[str2 release]; //---this is not OK as you do not own str2---

Attempting to release str2 will result in a runtime error because you cannot release an object not owned by you.

We can actually use [str2 release] if that is called before [str release]. If we do that, then the line [str release] will cause an error because now str as well as str2 are both dangling pointers, and supposedly when release was sent to the object the first time, the reference count became 0, and dealloc was called immediately, and the memory was freed by the C function free().

Is the above correct, or maybe there is something else to be corrected?

like image 623
Jeremy L Avatar asked May 13 '12 13:05

Jeremy L


4 Answers

Don't think of it in terms of managing memory, but in terms of object ownership. You obtain ownership of an object when you allocate it, retain it, or copy it. You are responsible for releasing exactly the objects you own, not others.

In your example the assignment to str2 does not take ownership of the object, but if you really need a second "owning" reference to it, then you ought to do [str2 retain], after which it is not an error to do [str release]; [str2 release];. This is also what would happen automatically using ARC, unless you annotated str2 as a weak reference. (Of course in this simple case the unnecessary retain/release could be optimized away internally by the compiler.)

like image 96
Arkku Avatar answered Nov 16 '22 17:11

Arkku


Your guess is correct: The book uses fuzzy language (even though the implications are correct) in an effort to simplify pointers away:

You own the object that str and str2 point to.

This of course means that you can only release the object once (or rather however often it was retained - once in your example, implicitly, by alloc), and whether you do so through str or str2 (or any other means) is insignificant.

In practice, you should treat your variables as if you owned them, though. This makes it much easier to keep track of retain/release pairs, and you cannot rely on the fact that nobody changed the value of one of these variables somewhere in between.

It is good practice (but not necessary) to set all variables that point to a deallocated instance to nil afterwards.

To delve a bit into the technical details (which really should be treated as what they are: Implementation details; artifacts of a private API):

Technically, nobody owns the object. The object has a counter of the number of times it was retained (which you can find out by calling anObject retainCount - but you shouldn't, not least because some objects have a bogus retainCount, and because it's really none of your concern). When an object is alloced, its retainCount is 1. Every time it is sent retain ("it is retained"), its retainCount goes up by 1, and every time it is sent release ("it is released"), its retainCount is decreased by 1.

Once the retainCount of an object reaches zero, it is deallocated (and its dealloc method is called).

Who sent all those retain/release messages (and through which variables) is not important.

Again: These are implementation details. They're artifacts of the way Objective-C/Cocoa do their memory management. Treat them like any private API: It's good to be curious, but never rely on internals. Only ever use the public API (in this case, retain/release and autorelease pools) in production code.

NOTE: Some objects (for instance some singletons) override the default retain/release methods. Never trust the retainCount you get from an object, other than for curiosity (look at the retainCount of [UIColor clearColor] for instance).

For more thoughts on this topic, this question and its answers are probably a nice summary/starting point.

That said, consider switching to ARC, which will rid you of almost all memory management troubles.

like image 36
fzwo Avatar answered Nov 16 '22 18:11

fzwo


I thought ownership is by object, not variable or pointer... so we can't say we "own str" or "own str2"... we own an object, which is pointed to by either str or str2, and if we use [str release] or [str2 release], it is all the same.

This is correct.

I think what the author means by "we own str" ist that you own that string instance. Not the pointer or the variable. You could theoretically release the object using an other pointer. But it's generally a better idea to release using the variable you used to initialize the object.

like image 2
DrummerB Avatar answered Nov 16 '22 17:11

DrummerB


I think the other answers are wrong or incomplete.

Ownership is defined by who releases a resource. An object doesn’t (usually) own itself, it is owned.

Again: the owner is whoever is responsible for releasing the memory.

In your code, str has declared its ownership of the object, str2 has not. In order for str2 to also own the object (to share str’s ownership), you’d need to retain it:

[str2 retain];

Now you could later say,

[str2 release];

to relinquish str2’s claim to ownership, and the same goes for str.

On the other hand, with ARC, all (reference-counting) pointers to a resource are its shared owners. In this scenario, all pointers are responsible for keeping track of the object reference count, and releasing the object once they determine that they are the sole owners and go out of scope.

To reiterate: Ownership is not by object. Ownership is by pointers to an object, and the owner of those pointers, but only if those pointers might be released in some scenario. Pointers are non-owning if there is no scenario in which they would release the resource. In this case, they are called weak.

The concept of a weak pointer would make no sense if objects owned themselves (since all pointers would be weak).

like image 1
Konrad Rudolph Avatar answered Nov 16 '22 18:11

Konrad Rudolph