Ignore 'Object sent -autorelease too many times" warning - iphone

When running Analyzer, I receive the "Object sent -autorelease too many times" warning. I know I'm doing something tricky (and am open to alternatives to accomplishing my goal).
Essentially, I wanted to keep a stack of specific types of controllers handy for sending messages from a central location. So, considering:
From 'ActionBroker' shared object:
NSMutableSet *liveActions;
liveActions = [NSMutableSet alloc] init];
...
CLViewController *action = [[[actionClass alloc] init] autorelease];
if (!action) {
return nil;
}
[self.liveActions addObject: action];
// When adding an object, the retain count is increased. We want the action
// to dealloc, so that it might remove itself from the list...
[action release];
return action;
And the complementary dealloc code:
[[CLActionBroker sharedActionBroker] removeAction: self];
[super dealloc];
... and in removeAction:
[action retain];
[self.liveActions removeObject:action];
The above code works, I just get the nagging error. And the nagging sensation that I could probably solve the problem a different way.
One of the use cases for this code is to pass an 'handleOpenURL' request through a chain of open controllers and returning the first 'YES' response.

As I understand it, your intent is to have a set of controllers ("actions") in the set, which you could easily access from anywhere in your app. If one of these controllers is deallocated, it would automatically remove itself from the set.
There's a problem with this setup, though. As you've described it above, the controller is supposed to be removed from the liveActions set upon deallocation. But since an NSSet retains its members, your controller will never be deallocated so long as it is still in the liveActions set. -dealloc is only run when all retains have been balanced by a release.
This, then leads to your over-release, which leads to the warning. Since you've sent an extra release, -dealloc could be run while the controller is still in the liveActions set. But when you remove it from that set, it's going to send a release message to your object, which would take its retain count negative. That may or may not be safe, but in either case it's an ugly workaround.
What you really want, it seems, is a set that does not retain its members. This is normally a dangerous configuration, since it can lead to dangling pointers in the set. But if you're willing to manage the lifetime of the object and clear out those dangling pointers at the appropriate times, it turns out that it's quite doable. You just need to use a CFMutableSet instead of an NSMutableSet. And since the two are toll-free bridged, it doesn't even add that much complexity.
Setting up the CFMutableSet looks like this:
// The NULL for the third parameter tells the set to not do anything when
// an object is added to or removed from the set.
CFMutableSetRef cfLiveActions = CFSetCreateMutable(NULL, 0, NULL);
// Toll-free bridging makes this possible
NSMutableSet *liveActions = (NSMutableSet *)cfLiveActions;
After that, you can use it exactly as you would use any other NSMutableSet; this one will just be special in that it won't retain its members.

The problem:
CLViewController *action = [[[actionClass alloc] init] autorelease]; // +0 ownership
// ...
[self.liveActions addObject: action]; // liveActions takes ownership
// ...
[action release]; // -1 ownership
When you've alloced the object, you are responsible for it. But then when you autorelease it, you've fulfilled your obligation (and because you autoreleased instead of releasing, you can still use the object until the next turn of the runloop). You shouldn't release it again later.
Also:
[action retain];
[self.liveActions removeObject:action];
The retain is unnecessary.
(And here's another plug for beginning to switch to ARC, under which you won't have to worry about this!)
[Edit: misunderstood your question. Revised answer forthcoming.]
[Edit 2: never mind... even though I misread your intent, I believe my solution is still right.]

Related

Releasing an object but still able to use it

I had understood that once you release an object, you shouldn't use it as it will cause an error since it is not in memory anymore.
But reading thru this Apple guide, I found this code, and have also seen it before, but I would just move the [object release] to the end of my code, so as to avoid getting an error. But it seems that it is accepted and works. So, why does this work? How can it keep setting variables to dateAttribute after it's been released?
(Line 3 is the one in question):
NSMutableArray *runProperties = [NSMutableArray array];
NSAttributeDescription *dateAttribute = [[NSAttributeDescription alloc] init];
[runProperties addObject:dateAttribute];
[dateAttribute release];
[dateAttribute setName:#"date"];
[dateAttribute setAttributeType:NSDateAttributeType];
[dateAttribute setOptional:NO];
Got it from here: Creating a managed object model in code
There are few points we should discuss.
release does not always make the object deallocated. The object will be deallocated only at the "last" release, i.e. when the retain count drop to zero.
Despite of that, it is still hold true that you should not use the object after you release it, because it is possible that it might be deallocated already.
The NSMutableArray will retain the object until it is removed from the array, or the array itself be allocated.
The example take the advantage that the array will retain the reference when added, so the reference will not be deallocated yet after releasing dateAttribute. However, this is not a good style because its validity depends solely on the nature of the class NSMutableArray itself, and it breaks common rule that we should not use released reference.
Technically, this is bad style, however it does work.
NSMutableArray (the runProperties addObject) calls retain on the dateAttribute. Therefore, calling release does not destroy the dateAttribute (there is still one reference).
For readability and refactoring reasons, I would also place the call to release last.

Objective-C (iPhone) ivars and memory management

I am subclassing NSURLConnection, and used MGTwitterEngine as a base to help me get started. That may be irrelevant. However, I noticed in their code they don't use #property or #synthesize for their ivars. They have wrapped the ivars in accessor methods which look like this:
- (NSString *)identifier {
return [[_identifier retain] autorelease];
}
My question is two part. First, what effect does retain followed by autorelease have? It seems to me it would cancel itself, or worse yet leak.
Second, if I were to change the header file to have:
#property (nonatomic, retain, readonly) NSString* _identifier;
And used #synthesize indentifier = _identifier, wouldn't this do the same thing as the accessor method without having to write it?
Maybe it is just two different ways to do the same thing. But I wanted to ensure I have the correct understanding. Thanks.
Using #synthesize will actually only create a setter and a getter method. The code that is auto generated for you is guaranteed to use proper memory management, so that you do not need to worry.
MGTwitterEngines use of return [[ivar retain] autorelease] is actually the correct way to do it. Lets have two examples.
Assume a getter is defined as this:
-(Foo)foo {
return foo;
}
And then we execute this code:
bar = [[bar alloc] init]; // bar has aretain count of 1.
foo = bar.foo; // foo har a retain count of 1 (owned by bar).
[bar release]; // Bar and all it's ivars are released imidiatetly!
[foo doSomething]; // This will crash since the previous line released foo.
If we instead change the getter to this:
-(Foo)foo {
return [[foo retain] autorelease];
}
bar = [[bar alloc] init]; // bar has a retain count of 1
foo = bar.foo; // foo has a retain count of 2 (one owned by bar, 1 owned by autorelease pool).
[bar release]; // Bar and all it's ivars are released imidiatetly!
[foo doSomething]; // Will not crash since foo is still alive and owned by autorelease pool.
Hope this explains why you should always return properly autoreleased objects from all your getters. It is important that any return value can survive the deallocation of it's parent, since no class ca guarantee what a client will do with it's values once it is exposed to the wild.
Retain followed by autorelease does exactly what you might think it does. It sends the object a retain message and then sends it an autorelease message. Remember that autoreleasing an object adds that object to the autorelease pool but does not release it yet. The autorelease pool will send the object a release message at the end of the current iteration of the run loop. So, a retain followed by autorelease essentially says, "Make sure this object stays around until the end of the the current iteration of the run loop." If you need the returned value to hang around longer, you can retain it. If not, do nothing and the autorelease pool will handle it.
In this case, the string being sent retain and autorelease messages is a property. It's already retained by the parent object. So you might wonder why do this retain and autorelease thing at all? Well, there's no guarantee that the object won't release _identifier before the current iteration of the run loop ends. Consider this example:
- (NSString *)identifier { return _identifier; }
- (void)aMethod {
NSString *localId = [self identifier]; // localId refers to _identifier which is only retained by self
[self methodThatChangesIdentifierAndReleasesItsOldValue]; // self releases _identifier
NSLog(#"%#", localId); // crash, because localId (old value of _identifier) has been released
}
In this case, the returned identifier isn't retained and autoreleased. The NSLog line crashes because localId refers to a released string. However, had we used retain and autorelease in the getter, there would be no crash because localId would not be released until the end of the current iteration of the run loop.
As far as I know, your replacement with an identifier property would be just as good. It might not be identical code, but the effect should be the same.
Apple explains this well in Implementing Accessor Methods. The method quoted by you (named "Technique 1" by Apple) helps avoid bugs if the caller assigns a new value to the identifier property and then expects the retrieved value to still be available. It won't be needed most of the time but just returning the ivar value can lead to bugs that are hard to track down.
Generally one retains then autoreleases if you are returning something that you didn't own the first place. It will only leak if you own _identifier and there is a mismatch of retain/alloc/etc versus release/autorelease sent to that object.
Secondly, yeah you generally don't have to write the headers if you aren't doing something special beyond what the general boilerplate looks like. Apple has good documentation on properties, I suggest if you're still fuzzy, you look at those.

Is release without prior retain dangerous?

I have some code which I think has extra release statements.
Is the code incorrect?
What is the end result?
I don't understand memory management well yet - even after reading lots of articles and stackoverflow answers. Thanks for straightening me out.
Update: The attached snippet works fine, but other code has the over-release problem
NSMutableArray *points = [NSMutableArray new];
for (Segment *s in currentWorkout.segments) {
[points addObjectsFromArray:[s.track locationPoints]];
}
[routeMap update:points];
[points release];
Your code is correct, but inadvisable. new acts as an implied alloc, which creates the object with a retain count of 1.
I think the last time I used new was in 1992; it's not wrong, but alloc/init is considered better practice, because it is clearer what you are doing. Please read Apple's guide to memory management, it is a comprehensive summary of the situation.
No messages can safely be sent to a deallocated object. Once an object has been released a sufficient number of times, it's deallocated. Any further messages sent to that object are going to an object that isn't there anymore. The precise result isn't completely predictable, but it usually ends in a crash. If you're less lucky, it could end in much stranger ways — for example, you could theoretically wind up with an Object A getting dealloced early and Object B allocated in the same memory location, then Object B receiving messages meant for Object A that Object B does understand but isn't supposed to receive at that time.
Basically, follow the rules. Think of it in terms of ownership. If you've claimed ownership, you need to release that ownership. If you don't own the object, you must not release it.
Take a look at this article online: http://weblog.bignerdranch.com/?p=2 .
It seems to imply that calls to release without a corresponding preior call to retain will result in a BAD_ACCESS error.
A short answer is, if you increasing the retain count of an object and you no longer are using it you should release it, otherwise you shouldnt...
So when ever you do a [objectName alloc] you are increasing the count by 1, when you use such methods as [NSString stringWithString:] these methods return an autoreleased object so you dont need to release it...if you instead did something like [[NSString stringWithString:]retain] then you are increasing the strings retain count and you should release it after you are done using it.
Im not too sure if new increases the reference count (i suspect that it would), you can always check your retain count by doing [object retainCount]... though note that even if the retain count is greater than 0, it does not mean you need to release the object, because some other class might have a reference to the object and therefore has its retain count increased by one and its the responsibility of the other class holding the reference to release it.
Hope this helps
you should use:
NSMutableArray *points = [[NSMutableArray alloc] init];
[...]
[routeMap update:points]; //if routemap stores the points, it will need it's own release retain
[points release]; //if there is a retain in the method above, reference will not be cleared
if unsure, use the build->analyze command, it will search your code for leaked references
you can get the official memory management guide from https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/MemoryMgmt/Articles/MemoryMgmt.html

Objective-C memory model

I am attempting to wrap my head around one part of the Objective-C memory model (specifically on the iPhone, so no GC). My background is C/C++/Java, and I am having an issue with the following bit of code (also wondering if I am doing this in an "Objective-C way" or not):
- (NSSet *) retrieve
{
NSMutableSet *set;
set = [NSMutableSet new];
// would normally fill the set in here with some data
return ([set autorelease]);
}
- (void) test
{
NSSet *setA;
NSSet *setB;
setA = [self retrieve];
setB = [[self retrieve] retain];
[setA release];
[setB release];
}
start EDIT
Based on comments below, the updated retrieve method:
- (NSSet *) retrieve
{
NSMutableSet *set;
set = [[[NSMutableSet alloc] initWithCapacity:100] autorelease];
// would normally fill the set in here with some data
return (set);
}
end EDIT
The above code gives a warning for [setA release] "Incorrect decrement of the reference count of an object is not owned at this point by the caller".
I though that the "new" set the reference count to 1. Then the "retain" call would add 1, and the "release" call would drop it by 1. Given that wouldn't setA have a reference count of 0 at the end and setB have a reference count of 1 at the end?
From what I have figured out by trial and error, setB is correct, and there is no memory leak, but I'd like to understand why that is the case (what is wrong with my understanding of "new", "autorelease", "retain", and "release").
I though that the "new" set the reference count to 1. Then the "retain" call would add 1, and the "release" call would drop it by 1. Given that wouldn't setA have a reference count of 0 at the end and setB have a reference count of 1 at the end?
You're leaving out the autorelease. When -(void)test gets a set, its retain count is 0. You don't retain setA, so it already has a retain count of 0 when you try to release it, hence the error message.
The fundamental rule for memory management is quite simple: calls to alloc, new and copy* must be balanced by calls to release/autorelease. The former take ownership, the latter relinquish ownership.
The only tricky part is when dealing with shared objects, where you don't take ownership of an object, so it might be discarded in between the time you get a reference to it and when you use it. This has a simple solution: if in doubt, retain it.
You can make things even simpler by using properties in many situations.
Don't think in terms of absolute numbers. That can be very deceptive. Think of retains and releases as deltas if you must have a number — in this case, the autorelease has already balanced the new (a +1 delta and a -1 delta), so that method manages its memory correctly and the receiver doesn't need to do anything unless it wants to keep the object around longer.
Definitely read the memory management docs. It really is as simple as following the rules described there. It's a very simple contract of ownership where you claim ownership when you want an object to stick around and relinquish ownership when you don't care anymore. In the case above, you relinquish ownership in the retrieve method, so trying to relinquish ownership when you don't have it is obviously a bug.
As the profiler message hints, you should be thinking in terms of ownership. As noted in the memory management rules, whenever you have an object that you have created with +alloc, +new, -copy, or -mutableCopy, you own it and are responsible for releasing it eventually. (In fact, +new is just shorthand for [[MyClass alloc] init].)
-retain takes an object that you didn't initially own and makes you own it.
-release takes an object that you own and releases ownership of it.
-autorelease takes an object that you own and releases ownership of it, but also guarantees that the object will exist for at least a little bit longer.
Your -retrieve method does not transfer ownership of the object it returns. This is good—it follows the memory management rules (the method isn't +alloc, +new, -copy, or -mutableCopy). Therefore, using -release on it without using -retain is an error. It would be equally valid to not retain or release the result from -retrieve, as long as the object will have a temporary lifetime—your -autorelease guarantees temporary existence of the object.
http://www.macresearch.org/difference-between-alloc-init-and-new
You probably want
NSMutableSet *set = [[NSMutableSet alloc] initWithCapacity: someNumber];
or
NSMutableSet *set = [NSMutableSet setWithCapacity: someNumber];

Why should a self-implemented getter retain and autorelease the returned object?

Example:
- (NSString*) title {
return [[title retain] autorelease];
}
The setter actually retained it already, right? and actually nobody should bypass the Setter... so I wonder why the getter not just returns the object? It's actually retained already. Or would this just be needed in case that in the mean time another objects gets passed to the setter?
From here http://www.macosxguru.net/article.php?story=20030713184140267
- (id)getMyInstance
{
return myInstanceVar ;
}
or
- (id)getMyInstance
{
return [[myInstanceVar retain] autorelease] ;
}
What's the difference ?
The second one allows the caller to get an instance variable of a container object, dispose of the container and continue to play with the instance variable until the next release of the current autoreleased pool, without being hurt by the release of the instance variable indirectly generated by the release of its container:
aLocalVar = [aContainer getAnInstanceVar] ;
[aContainer release];
doSomething(aLocalVar);
If the "get" is implemented in the first form, you should write:
aLocalVar = [[aContainer getAnInstanceVar] retain];
[aContainer release];
doSomething(aLocalVar);
[aLovalVar release];
The first form is a little bit more efficent in term of code execution speed.
However, if you are writing frameworks to be used by others, maybe the second version should be recommanded: it makes life a little bit easier to people using your framework: they don't have to think too much about what they are doing…;)
If you choose the first style version, state it clearly in your documentation… Whatever way you will be choosing, remember that changing from version 1 to version 2 is save for client code, when going back from version 2 to version 1 will break existing client code…
It's not just for cases where someone releases the container, since in that case it's more obvious that they should retain the object themselves. Consider this code:
NSString* newValue = #"new";
NSString* oldValue = [foo someStringValue];
[foo setSomeStringValue:newValue];
// Go on to do something with oldValue
This looks reasonable, but if neither the setter nor the getter uses autorelease the "Go on to do something" part will likely crash, because oldValue has now been deallocated (assuming nobody else had retained it). You usually want to use Technique 1 or Technique 2 from Apple's accessor method examples so code like the above will work as most people will expect.
Compare this code
return [[title retain] release]; // releases immediately
with this
return [[title retain] autorelease]; // releases at end of current run loop (or if autorelease pool is drained earlier)
The second one guarantees that a client will have a non-dealloced object to work with.
This can be useful in a situation like this (client code):
NSString *thing = [obj title];
[obj setTitle:nil]; // here you could hit retainCount 0!
NSLog(#"Length %d", [thing length]); // here thing might be dealloced already!
The retain (and use of autorelease instead of release) in your title method prevents this code from blowing up. The autoreleased object will not have its release method called until AFTER the current call stack is done executing (end of the current run loop). This gives all client code in the call stack a chance to use this object without worrying about it getting dealloc'ed.
The Important Thing To Remember: This ain't Java, Ruby or PHP. Just because you have a reference to an object in yer [sic] variable does NOT ensure that you won't get it dealloc'ed from under you. You have to retain it, but then you'd have to remember to release it. Autorelease lets you avoid this. You should always use autorelease unless you're dealing with properties or loops with many iterations (and probably not even then unless a problem occurs).
I haven't seen this pattern before, but it seems fairly pointless to me. I guess the intent is to keep the returned value safe if the client code calls "release" on the parent object. It doesn't really hurt anything, but I doubt that situation comes up all that often in well-designed libraries.
Ah, ok. from the documentation smorgan linked to, it seems this is now one of the methods that Apple is currently recommending that people use. I think I still prefer the old-school version:
- (NSString *) value
{
return myValue;
}
- (void) setValue: (NSString *) newValue
{
if (newValue != myValue)
{
[myValue autorelease]; // actually, I nearly always use 'release' here
myValue = [newValue retain];
}
}