I am learning memory management, but I don't really understand why I should implement my attribute getter like this:
-(Weapon*)myWeapon
{
[myWeapon retain];
[myWeapon autorelease];
return myWeapon;
}
I understand what I wrote, but I can't imagine why it is important? Can you please explain why I should do this?
This is from the Memory Management Programming guide:
Technique 1
In technique 1, values returned by the getter are autoreleased within the calling scope:
- (NSString*) title {
return [[title retain] autorelease];
}
- (void) setTitle: (NSString*) newTitle {
if (title != newTitle) {
[title release];
title = [newTitle retain]; // Or copy, depending on your needs.
}
}
Because the object returned from the get accessor is autoreleased in the current scope, it remains valid if the property value is changed. This makes the accessor more robust, but at the cost of additional overhead. If you expect your getter method to be called frequently, the added cost of retaining and autoreleasing the object may not be worth the performance cost.
Technique 2
Like technique 1, technique 2 also uses an autorelease technique, but this time does so in the setter method:
- (NSString*) title {
return title;
}
- (void) setTitle: (NSString*) newTitle {
[title autorelease];
title = [newTitle retain]; // Or copy, depending on your needs.
}
The performance of technique 2 is significantly better than technique 1 in situations where the getter is called much more often than the setter.
Technique 3
Technique 3 avoids the use of autorelease altogether:
- (NSString*) title {
return title;
}
- (void) setTitle: (NSString*) newTitle {
if (newTitle != title) {
[title release];
title = [newTitle retain]; // Or copy, depending on your needs.
}
}
The approach used by technique 3 is good for frequently called getter and setter methods. It is also good for objects that do not want to extend the lifetime of their values, such as collection classes. Its disadvantage is that the old value may be deallocated immediately (if there are no other owners), which will cause a problem if another object is maintaining a non-owning reference to it. For example:
NSString *oldTitle = [anObject title];
[anObject setTitle:#"New Title"];
NSLog(#"Old title was: %#", oldTitle);
If anObject was the only object that owned the original title string, then the string will be deallocated after the new title is set. The log statement would then cause a crash as oldTitle is a freed object.
EDIT: Basically the point of retaining and then auto-releasing is to ensure that the object won't get deallocated if the property value is changed before the calling scope has a chance to retain it. This isn't usually an issue unless you've got asynchronous code. In most situations - (Weapon *)myWeapon { return myWeapon; } is just fine (plus it's faster).
As ACBurk says, but there is a good description here:
http://vgable.com/blog/2009/03/31/how-to-write-cocoa-object-getters/
Related
Question
In my ARC project I have a class that manages objects, called LazyMutableArray. Some of the objects are actually nil, but users of my collection will never know about this; therefore I made it a subclass of NSMutableArray, and it tries to do "the same thing". In particular, objects are retained when added.
Now let's take a look at a memory behavior of other methods. It turns out that the NSArray destruction methods are documented by Apple to be an exception to this rule, in that they release, not autoreleased object.
There is some debate as to whether the combination of addObject: + objectAtIndex: + array destruction is documented by Apple to be never autoreleasing or simply happens to be in the examples I tested and in the example Apple includes.
How can I create in my subclass a method with exact same memory semantics?
Last update
After some thought, I've decided implementation based on NSMutableArray is more appropriate in this case compared to NSPointerArray. The new class, I should note, has the same retain/autorelease pair as the previous implementation.
Thanks to Rob Napier I see that no modification of my objectAtIndex: method would change this behavior, which answers my original question about this method.
On a practical level, several people said that any method can tackle an extra retain/autorelease pair for no reason; it's not reasonable to expect otherwise and not reasonable to try to find out which methods do this and which do not. It's been therefore a great learning opportunity for me on several levels.
Code (based on NSMutableArray) is available at GitHub: implementation, header, test (that's -testLazyMutableMemorySemantics).
Thank you all for participating.
Why I try to subclass NSMutableArray:
Subclassing foundation objects, I agree, is not always an appropriate solution. In tho case I have objects (in fact, OData resources), most of which have subobjects. The most natural class for an array of subobjects is obviously NSArray. Using a different class doesn't seem to make sense to me.
But for an OData collection this "array of sub objects", while, being an NSArray, must have a different implementation. Specifically, for a collection of 1000 elements, servers are encouraged to return collection in batches of (say)20, instead of all at once. If there is another pattern appropriate in this case, I'm all ears.
Some more detail in how I found this
I unit test the hell out of this collection, and values can be put into array, read from the array, and so forth. So far, so good. However, I realized that returning the object increases its retain count.
How do I see it? Suppose I insert two objects into lazy array lazy, one held weakly, one held strongly (*see the code *). Then retain count of weakSingleton is, as expected, 1. But now I read element:
XCTAssertEqual(weakSingleton, lazy[0], #"Correct element storage"); // line B
And in the debugger I see the retain count go up to 2. Of course, -retainCount may give me wrong information, so let's try to destroy the reference in array by
lazy[0] = nil; // yep, does the right thing
XCTAssertNil(weakSingleton, #"Dropped by lazy array"); // line C <-- FAIL
indeed, we see that weakSingleton is not released.
By now you probably guess that it's not just a retain, it's an autoreleased retain — putting an #autorelease around line B releases the weakSingleton. The exact source of this pair is not obvious, but seems to come from NSPointerArray -addPointer: (and unfortunately not from ARC's [[object retain] autorelease]). However, I don't want to return an autoreleased object and make method semantics different from its superclass!
After all, the method I'm overriding, NSMutableArray -objectAtIndex:`, doesn't do that; the object it returns will dealloc immediately if an array is released, as noted in the Apple's example. That's what I want: modify the method around line A so that the object it returns does not have an extra retain/autorelease pair. I'm not sure the compiler should even let me do it :)
Note 1 I could turn off ARC for a single file, but this would be my first non-ARC Objective-C code. And in any case the behavior may not some from ARC.
Note 2 What the fuss? Well, in this case I could change my unit tests, but still, the fact is that by adding or deleting line B, I'm changing the result of unit test at line C.
In other words, the described behavior of my method [LazyMutableArray -objectAtIndex] is essentially that by reading an object at index 0, I'm actually changing the retain count of this object, which means I could encounter unexpected bugs.
Note 3 Of course, if nothing is to be done about this, I'll document this behavior and move on; perhaps, this indeed should be considered an implementation detail, not to be included into tests.
Relevant methods from implementation
#implementation LazyMutableArray {
NSPointerArray *_objects;
// Created lazily, only on -setCount:, insert/add object.
}
- (id)objectAtIndex:(NSUInteger)index {
#synchronized(self) {
if (index >= self.count) {
return nil;
}
__weak id object = [_objects pointerAtIndex:index];
if (object) {
return object;
}
}
// otherwise do something else to compute a return value
// but this branch is never called in this test
[self.delegate array:self missingObjectAtIndex:index];
#synchronized(self) {
if (index >= self.count) {
return nil;
}
__weak id object = [_objects pointerAtIndex:index];
if (object) {
return object;
}
}
#throw([NSException exceptionWithName:NSObjectNotAvailableException
reason:#"Delegate was not able to provide a non-nil element to a lazy array"
userInfo:nil]);
}
- (void)createObjects {
if (!_objects) {
_objects = [NSPointerArray strongObjectsPointerArray];
}
}
- (void)addObject:(id)anObject {
[self createObjects];
[_objects addPointer:(__bridge void*)anObject];
}
The complete test code:
// Insert two objects into lazy array, one held weakly, one held strongly.
NSMutableArray * lazy = [LazyMutableArray new];
id singleton = [NSMutableArray new];
[lazy addObject:singleton];
__weak id weakSingleton = singleton;
singleton = [NSMutableDictionary new];
[lazy addObject:singleton];
XCTAssertNotNil(weakSingleton, #"Held by lazy array");
XCTAssertTrue(lazy.count == 2, #"Cleaning and adding objects");
// #autoreleasepool {
XCTAssertEqual(weakSingleton, lazy[0], #"Correct element storage");
XCTAssertEqual(singleton, lazy[1], #"Correct element storage");
// }
lazy = nil;
XCTAssertNotNil(singleton, #"Not dropped by lazy array");
XCTAssertNil(weakSingleton, #"Dropped by lazy array");
The last line fails, but it succeeds if I change first line to lazy = [NSMutableArray new] or if I uncomment #autoreleasepool.
First, I would not make this subclass. This is exactly what NSPointerArray is for. Wrapping that into an NSArray obscures important details that this approach can break. For example, what is the correct behavior for [NSArray arrayWithArray:lazyMutableArray] if lazyMutableArray includes NULLs? Algorithms that assume that NSArray can never include NULL need to be wary of the fact that this one can. It's true that you can get similar issues treating a non-retaining CFArray as an NSArray; I speak from experience that this is exactly why this kind of subclass can be very dangerous (and why I stopped doing that years ago). Don't create a subclass that cannot be used in every case that its superclass can be used (LSP).
If you have a collection with new semantics, I would subclass it from NSObject, and have it conform to <NSFastEnumeration>. See how NSPointerArray is not a subclass of NSArray. This was not an accident. Faced with the same problem, note the direction Apple chose.
By now you probably guess that it's not just a retain, it's an autoreleased retain — putting an #autorelease around line B releases the weakSingleton. This seems to be because line A under ARC translates to [[object retain] autorelease]. However, I don't want to return an autoreleased object and make caller remember this!
The caller should never assume anything else. The caller is never free to assume that a method does not add balanced autoreleases. If a caller wants the autorelease pool to drain, that is their responsibility.
All that said, there is some benefit to avoiding an extra autorelease if it's not required, and it's an interesting learning opportunity.
I would start by reducing this code to the simplest form, without your subclass at all. Just explore how NSPointerArray works:
__weak id weakobject;
#autoreleasepool
{
NSPointerArray *parray = [NSPointerArray strongObjectsPointerArray];
{
id object = [NSObject new];
[parray addPointer:(__bridge void*)object];
weakobject = object;
}
parray = nil;
}
NSAssert(!weakobject, #"weakobject still exists");
My structure here (such as the extra nesting block) is designed to try to avoid accidentally creating strong references I don't mean to make.
In my experiments, this fails without the autoreleasepool and succeeds with it. That indicates that the extra retain/autorelease is being added around or by the call to addPointer:, not by ARC modifying your interface.
If you're not using this implementation for addObject:, I'd be interested in digging deeper. It is an interesting question, even if I don't believe you should be subclassing this way.
I'm going to elaborate on why I said this "looks a lot like a homework assignment." This will likely earn me many down votes, but it will also server as a good learning case for others who later find this question.
Subclassing NSMutableArray not a goal of a program. It is a means to achieve something else. If I were to venture a guess, I expect you were trying to create an array that lazily creates the object when they are accessed. There are better ways to do this without dealing with memory management yourself.
Here's an example of how I would implement a lazy loading array.
#interface LazyMutableArray : NSMutableArray
- (id)initWithCreator:(id(^)(int))creator;
#end
#interface LazyMutableArray ( )
#property (nonatomic, copy) id (^creator)(int);
#property (nonatomic, assign) NSUInteger highestSet;
#end
#implementation LazyMutableArray
- (id)initWithCreator:(id(^)(int))creator
{
self = [super init];
if (self) {
self.highestSet = NSNotFound;
self.creator = creator;
}
return self;
}
- (id)objectAtIndex:(NSUInteger)index
{
id obj = nil;
if ((index < self.highestSet) && (self.highestSet != NSNotFound)) {
obj = [super objectAtIndex:index];
if ([obj isKindOfClass:[NSNull class]]) {
obj = self.creator(index);
[super replaceObjectAtIndex:index withObject:obj];
}
} else {
if (self.highestSet == NSNotFound) {
self.highestSet = 0;
}
while (self.highestSet < index) {
[super add:[NSNull null]];
self.highestSet += 1;
}
obj = self.creator(index);
[super add:obj];
self.highestSet += 1;
}
return obj;
}
Fair Warning: I'm not compiling or syntax checking any of this code. It probably has a few bugs in it, but it should generally work. Additionally, this implementation is missing an implementation of add:, count, removeObjectAtIndex:, insertObject:atIndex:, and possibly replaceObjectAtIndex:withObject:. What I show here is just to get you started.
I was told by a fellow StackOverflow user that I should not use the getter method when releasing a property:
#property(nonatmic, retain) Type* variable;
#synthesize variable;
// wrong
[self.variable release];
// right
[variable release];
He did not explain in detail why. They appear the same to me. My iOS book said the getter on a property will look like this:
- (id)variable {
return variable;
}
So doesn't this mean [self variable], self.variable, and variable are all the same?
For a retained property with no custom accessor, you can release the object by:
self.variable = nil;
This has the effect of setting the ivar (which may not be called 'variable' if you have only declared properties) to nil and releasing the previous value.
As others have pointed out, either directly releasing the ivar (if available) or using the method above is OK - what you must not do is call release on the variable returned from a getter.
You can optionally write custom getter behavior, which may result in completely different behavior. So, you cannot always assume that [variable release] has the same results as [self.variable release].
As well, you can write custom properties without an exclusive ivar backing them... it can get messy fast if you start releasing objects from references returned by getters!
There may be additional reasons that I'm unaware of...
A typical getter will look more like this:
- (id)variable {
return [[variable retain] autorelease];
}
So if you use [self.variable release] you have an additional retain and autorelease that you don't really need when you just want to release the object and that cause the object to be released later than necessary (when the autorelease pool is drained).
Typically, you would either use self.variable = nil which has the benefit that it also sets the variable to nil (avoiding crashes due to dangling pointers), or [variable release] which is the fastest and may be more appropriate in a dealloc method if your setter has custom logic.
not all getters take this form:
- (id)variable { return variable; }
...that is merely the most primitive form. properties alone should suggest more combinations, which alter the implementation. the primitive accessor above does not account for idioms used in conjunction with memory management, atomicity, or copy semantics. the implementation is also fragile in subclass overrides.
some really brief examples follow; things obviously become more complex in real programs where implementations become considerably more complex.
1) the getter may not return the instance variable. one of several possibilities:
- (NSObject *)a { return [[a copy] autorelease]; }
2) the setter may not retain the instance variable. one of several possibilities:
- (void)setA:(NSObject *)arg
{
...
a = [arg copy];
...
}
3) you end up with memory management implementation throughout your program, which makes it difficult to maintain. the semantics of the class (and how it handles instance variables' ref counting) should be kept to the class, and follow conventions for expected results:
- (void)stuff:(NSString *)arg
{
const bool TheRightWay = false;
if (TheRightWay) {
NSMutableString * string = [arg mutableCopy];
[string appendString:#"2"];
self.a = string;
[string release];
// - or -
NSMutableString * string = [[arg mutableCopy] autorelase];
[string appendString:#"2"];
self.a = string;
}
else {
NSMutableString * string = [arg mutableCopy];
[string appendString:#"2"];
self.a = string;
[self.a release];
}
}
failing to follow these simple rules makes your code hard to maintain and debug and painful to extend.
so the short of it is that you want to make your program easy to maintain. calling release directly on a property requires you to know a lot of context of the inner workings of the class; that's obviously bad and misses strong ideals of good OOD.
it also expects the authors/subclassers/clients to know exactly how the class deviates from convention, which is silly and time consuming when issues arise and you have to relearn all the inner details when issues arise (they will at some point).
those are some trivial examples of how calling release on the result of a property introduces problems. many real world problems are much subtler and difficult to locate.
Apple's Memory Management Programming Guide shows three officially sanctioned techniques for writing accessor methods that need to retain or release object references.
In the case of the first two techniques (reproduced below), the Apple documentation says that "[t]he performance of technique 2 is significantly better than technique 1 in situations where the getter is called much more often than the setter."
// Technique 1
- (NSString*) title
{
return [[title retain] autorelease];
}
- (void) setTitle: (NSString*) newTitle
{
if (title != newTitle)
{
[title release];
title = [newTitle retain]; // Or copy, depending on your needs.
}
}
// Technique 2
- (NSString*) title
{
return title;
}
- (void) setTitle: (NSString*) newTitle
{
[title autorelease];
title = [newTitle retain]; // Or copy, depending on your needs.
}
Is this the only difference between technique 1 and technique 2, or does using one over the other have other subtle consequences of which I might need to be aware? And if technique 2 uses a better performing getter, does it follow that technique 1 uses a better performing setter since title gets an explicit (and presumably immediate) release?
The getter from 2 and the setter from 1:
- (NSString*) title
{
return title;
}
- (void) setTitle: (NSString*) newTitle
{
if (title != newTitle)
{
[title release];
title = [newTitle retain]; // Or copy, depending on your needs.
}
}
The second getter is fragile (it will crash if somebody access's the object's title and then releases the object), so the first is generally preferable even if marginally slower.
The first setter is more efficient and will work even in situations where an autorelease pool doesn't exist, so it's preferable. The reason it's more efficient is not just because of autorelease vs. release — it doesn't do any work at all if you try to set the property to its existing value.
I've been reading an apple document on Memory Management and am now a bit confused regarding the recommended implementation of Accessors. Apple cites 3 approaches in implementing accessors.
Technique 1
I've copied the code from the first technique which reflects: "Getter retains and autoreleases the value before returning it; setter releases the old value and retains (or copies) the new value." This first technique is stated to be more robust but suffers performance penalties on frequently called getters.
- (NSString*) title {
return [[title retain] autorelease];
}
- (void) setTitle: (NSString*) newTitle {
if (title != newTitle) {
[title release];
title = [newTitle retain]; // Or copy, depending on your needs.
}
}
skipping Technique 2
Technique 3
The third technique is better for frequently called setters and getters. This is also the method I've always followed.
- (NSString*) title {
return title;
}
- (void) setTitle: (NSString*) newTitle {
if (newTitle != title) {
[title release];
title = [newTitle retain]; // Or copy, depending on your needs.
}
}
My questions are:
(Technique 1) The setter first releases the existing value even if it doesn't point to anything. This would send a message to nil which I understand is supported in Objective-C but still looks odd. Am I understanding this correctly?
(Technique 1) Why is the retain stacked inside an autorelease?
(Technique 1) Is the caller whom uses the getter expected to call release after they're done with the object?
The apple developer documentation page can be found at: Memory Management Programming Guide - Accessor Methods
(Technique 1) The setter first
releases the existing value even if it
doesn't point to anything. This would
send a message to nil which I
understand is supported in Objective-C
but still looks odd. Am I
understanding this correctly?
Yup. Messages to nil matter not.
(Technique 1) Why is the retain
stacked inside an autorelease?
That guarantees that the following doesn't break:
x = [foo title];
[foo setTitle: #"bar"];
[x length]; // x has been released, possibly, if -title didn't retain/autorelease
(Technique 1) Is the caller whom uses
the getter expected to call release
after they're done with the object?
No.
Sending a message to nil is defined to do nothing. This setter is an excellent example of how that allows you to write simpler code: [title release] instead of if (title != nil) [title release];. Note also that no special checks for nil are necessary on newTitle.
The retain/autorelease pair in the getter mean that the returned object will remain valid through the lifetime of the current function call (technically, until the autorelease pool is drained), even if the setter is called. The documentation you cite gives an example of how that can be helpful if there's a variable with a "non-owning reference" to the value.
NO. The value has already been autoreleased; caller must not release it again.
I am a little curious about the last lines in the two examples presented below (i.e. planetName = [value ??????]) My understanding is that the 1st example with the copy is best as that takes a copy of the string object to protect against the original string object being changed elsewhere.
I am also a little confused by the last line in the 2nd example, again my understanding was that the value object was being passed into the method, I guess I am confused as value is being retained with no associated release? Can someone set me straight?
- (void)setPlanetName:(NSString *)value {
if (planetName != value) {
[planetName release];
planetName = [value copy];
}
}
.
- (void)setPlanetName:(NSString *)value {
if (planetName != value) {
[planetName release];
planetName = [value retain];
}
}
Given:
- (void)setPlanetName:(NSString *)value {
if (planetName != value) {
[planetName release];
planetName = [value copy];
}
}
The -copy ensures that if someone passes in an instance of NSMutableString as value, then planetName won't change in your instances out from under you.
A good defensive programming pattern. Note that -copy is free on immutable strings; -copy just bumps the retain value and returns self (the instance of the string that was copied).
Now, consider your second example:
- (void)setPlanetName:(NSString *)value {
if (planetName != value) {
[planetName release];
planetName = [value retain];
}
}
Perfectly valid and works fine, just not as defensive.
In both cases, planetName must be released in your -dealloc method.
- (void) dealloc
{
[planetName release];
planetName = nil; // defensive
[super dealloc];
}
It doesn't matter if the string is copied, retained, or was originally a constant string that was passed into your setter. If you retain it (or implied retain it through copy), you must release it.
Note that you can think of this as "escape patterns". Whenever the existing value of planetName escapes your object, you must release it. That can happen when the object is deallocated or when a new value of planetName is set, hence the -release in the setters.
Or, if on Mac OS X, you could turn on garbage collection and be done with it. In any case, you should be using #property & #synthesize to automatically generate the getter/setter pair.
in the class's dealloc method, there should be another [planetName release] there, which will handle releasing of any instance variables. If that is present then there is no memory leak to worry about.
As for your other question, yes copy is used if you potentially have a mutable object that you don't want to allow other code to be able to modify what your class expects. You are expected to release any object that you call copy on, as it returns something with a retain count of 1. Also, in the case of immutable objects (like NSStrings vs. NSMutableStrings) copy just calls retain since there is no need to make a full copy of something that is immutable.