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.
Related
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.]
If I have a class named Foo and I have this function + getIds that should return ids. Would the correct signature of + getIds look like this:
+ (NSArray *)getIds {
NSMutableArray *ids = [[[NSMutableArray alloc] init] autorelease];
return ids;
}
What I'm wondering is that if I should use autorelease on *ids? There is no other way I assume? I can't do [ids release] after the return statement right?
You can send autorelease message along with alloc, init messages. You can also do, return [ids autorelease]; Note: You should not do both at the same time ;-)
You can not return [id release], because release method itself returns nothing.
The typically-correct memory management for returned objects is to have the called method set it as an autoreleased object, except when the method name contains "copy", "new" or "alloc". In those cases (copy/new/alloc), the returned object is retained, and the caller owns it (i.e. the caller is responsible for making sure they are released).
The code you wrote in the question will do the correct thing - it will return an autoreleased object.
When the caller gets the NSArray back, they can use the object as much as they like, and if they don't need the object in future calls, then they don't need to do any extra memory management. At the end of the run loop, the NSArray will be released, which is the desired behavior. If the caller does need the object to live longer, then they have to call retain on it (or something equivalent to that, such as calling something else that calls retain on it), and then they take the responsibility to call release on it later.
Useful stuff:
Apple's iOS memory management guide
My personal memory management guidelines (shorter, more biased)
Understanding run loops
Also, this will all go away when ARC (automatic reference counting, in iOS 5) becomes the norm.
You are already autoreleasing the array, so calling autorelease a second time would be an error that might result in a crash. The fact that you can't do a release after the return (you've left the function by then) is one of the reasons autorelease exists.
About whether the method should return an autoreleased as opposed to a retained object: Only methods that start with alloc or new or contain copy (as in mutableCopy) shall return retained objects. All other method shall return autoreleased objects.
When a method returns an object that is taken from and NSMutableArray does the object must be autoreleased? Check the following method. Also should I autorelease the nil value?
-(NSObject*)getElementByID:(NSString*)ID{
for(int i=0;i<[elements count];i++){
NSObject *element = (NSObject*) [elements objectAtIndex:i];
if([element.key isEqualToString:ID]){
return [element autorelease];
}
}
return nil;
}
You must not autorelease element because you are not an owner of it (you have not put a retain on it). You would have become an owner of it if you acquired it using alloc, new or retain. Since you acquired this object calling objectAtIndex:, you do not own it. See Three Magic Words. Calling autorelease here will cause a crash later do to over-release.
Your method name is incorrect and breaks KVC. A method that begins with get must take a pointer that will be updated with the result. This should be elementForID:. As noted above with the three magic words, naming in ObjC is very important to writing stable code
As a side note, it is traditional to use id is most cases rather than NSObject*. They mean slightly different things, but typically id is correct.
You never need to do any memory management related things to nil. So, no, you should not send autorelease to nil.
You also should not need to send autorelease to the element object that you are returning from your elements array. That object you are returning will remain in memory by virtue of elements itself having retained it. If the calling method would like to retain the value that you return, it may. But if that calling method only uses the returned value within its own scope, it is safe for it to do so without retaining it.
If I have a class
#interface Foo {
NSString *temp;
}
#property(nonatomic, copy) NSString *temp;
#end
I understand that upon assignment, the old temp will get released and the new one will be assigned using temp = [newTemp copy]. And going by memory management rules, you are supposed to do [temp release] in the dealloc method of Foo, right?
What I don't understand is what happens if the setter was never used - you still have the [temp release] in the dealloc, so it's releasing something with a retain count of 0. Can someone clarify this for me?
There are two possibilities.
Since you never set it, it's nil. Sending release to nil is just fine. So no problem there.
Your init routine makes a default value for temp. Then it is a real object, and sending it release is also ok.
No problem all around! In neither case are you sending a message to an object with a retain count of 0.
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];
}
}