Why Obj-C Instance Have 1 Retain Count Just Created

Why alloc method can add retain count

You cannot find generic code that adds one in +alloc. Usually inside +alloc the object is newly created and gets the RC 1. (So you can say that 1 is added, because the object before its creation has an RC of 0. Of course, this is not formally correct, because before the creation there is no object, therefore it cannot have an RC. Akin of the zero is null antipattern.)

However, classes can overwrite +alloc to return an existing object instead of a new one. For example this has been done in the past for implementing singletons. In such a case +alloc had to signal the new reference (+alloc does an ownership transfer) and really had to add 1. Something like this (sample code):

+(id)alloc
{
if(mySingleton==nil) // it is not already created
{
return mySingleton = [super alloc];
}
return [mySingleton retain]; // ownership transfer
}

I think the idea of saying "+1" instead of "1" in some articles is, that you should view every reference separately. So there is no absolute value of RC. Whatever you do with a reference and its object is relative to the situation before you did it. For this reason some authors always describe the RC with "+1" and "-1". Of course, this is meaningless, if an object is newly created.

What increases an object's retain count?

You are correct that the retain count is 2 after adding it to an array. However, you should only worry about the retain counts you add to the item explicitly.

Retaining an object is a contract that says "I'm not done with you, don't go away." A basic rule of thumb (there are exceptions, but they are usually documented) is that you own the object when you alloc an object, or create a copy. This means you're given the object with a retain count of 1(not autoreleased). In those two cases, you should release it when you are done. Additionally, if you ever explicitly retain an object, you must release it.

So, to be specific to your example, when you create the Person, you have one retain count on it. You add it to an array (which does whatever with it, you don't care) and then you're done with the Person, so you release it:

Person *p = [[Person alloc] init]; //retain 1, for you
[array addObject:p]; //array deals with p however it wants
[p release]; //you're done, so release it

Also, as I said above, you only own the object during alloc or copy generally, so to be consistent with that on the other side of things, you should return the array autoreleased, so that the caller of the getPeople method does not own it.

return [array autorelease];

Edit:
Correct, if you create it, you must release it. If you invest interest in it (through retain) you must release it.

Method returns an Objective-C object with a +1 retain count

The other answers already explain the problem in depth, anyway these are some common patterns that you can use to avoid this error:

NSIndexPath *ip = [[NSIndexPath alloc] init];
self.indexPath = ip;
/* ... */
[ip release];

indexPath = [[NSIndexPath alloc] init];

self.indexPath = [[[NSIndexPath alloc] init] autorelease];

self.indexPath = [NSIndexPath indexPathWithIndex:...];

Conditions in which retainCount increases or decreases

retainCount of an object changes in the following cases:

  • When you create an object(new or
    alloc, copy or mutablecopy), it has a
    retain count of 1.

  • When you send an object a retain
    message, its retain count is

    incremented by 1.

  • When you send an object a release
    message, its retain count is

    decremented by 1.

  • When you send a autorelease message
    to an object, its retain count
    will be decremented by 1(not

    immediately as in case of release but
    some time in the future)

You can view this post to get a detailed info on how memory management works in iPhone.

Why does an object with a retain count of 0 respond to a message?

Just because an object's retain count goes to 0 and its dealloc method is called, doesn't mean the memory used by the object is instantly turned to garbage. The deallocated object could possibly sit in memory, intact, for a while before the memory space is reused for something else.

That seems to be the case here. The call to log host after it's been deallocated finds that the memory for the deallocated object is still intact so accessing its data works.

But it seems in your test on a Mac results in the memory being handled differently causing the exception.

RetainCount OK to use in this instance?

retainCount is taboo, unreliable, unpredictable, and in general shouldn't be used.

You can rely on the value of retainCount IFF your objects don't pass through any code that's opaque to you, such as any Cocoa framework. In practice, this is almost impossible to achieve, thus the warning. The internals of Cocoa may be passing your object around, retaining, releasing, and putting it into autorelease pools many times and for many reasons, and you can't rely on its absolute value at any given point.

The catch is that the thread increases the retain count of the owner, in my case the class that instantiated it.

That's a retain cycle. The answer here is to find a way to break that cycle, not to subvert the reference counting mechanism. There must be some point before deallocation when either your thread or the owning object knows that the work the thread is performing is done (or needs to stop prematurely).

It sounds like the owning object is the interface for client code to the work the thread is doing. This owning object needs a "shutdown now" method that needs to be called (and documented as "must be called") before its owner releases it. In that shutdown method, you can break the cycle by releasing the thread.

I'm not exactly sure what's going on that the thread is retaining its creator (the cycle is a pretty clear indication that something is wrong with your ownership model) -- I'd guess you're using NSThread and initWithTarget:..., with the target being the creating/owning object. This is a bit of a mixup of the standard MVC pattern -- the owner of the thread is a "controller", the thread itself (and the code it runs) more of a "model".

The controller should not contain the thread's code, in other words. I'd recommend that you factor out the thread's code into another object to use as the target. Then the controller object owns both the thread itself and the "work" target object, with neither of them owning the controller. Voilà, no cycle!



Related Topics



Leave a reply



Submit