Clarification on when to release pointers after allocating - objective-c

In my last question (here), I had an issue where I was getting an EXC_BAD_ACCESS because I was releasing the variable I had just allocated:
NSMutableArray* s = [[NSMutableArray alloc] init];
stack = s;
[s release];
should have been
NSMutableArray* s = [[NSMutableArray alloc] init];
stack = s;
However, stack is a retained property of my class. It's declared like so:
#interface StateStack ()
#property (nonatomic, retain) NSMutableArray* stack;
#end
I was under the impression that when you assign a 'retain' variable, it automatically increments the retainCount of the object. So you are supposed to start by releasing your pointer (as here).
Why are these two cases different? Thanks!

Because you had to assign the property, not the instance variable. When you assign to the property it's going to retain the variable again and then you're not going to have the issue. Here's how your code should have been:
NSMutableArray* s = [[NSMutableArray alloc] init];
self.stack = s;
[s release];
This way you're not assigning to the variable, but using the property (that's, in fact, a method). If you did not release in this case then you'd have a memory leak in your code.
When you did stack = s you assigned directly to the instance variable and the array was never retained.

There is no such thing as a "retain variable". It's a retain property — meaning the setter method behind the property retains the new value and releases the old one. But assigning to a variable just assigns. In fact, the reason people generally recommend assigning directly to the instance variable in init is specifically so that it doesn't go through the setter, because the setter could conceivably have side effects you don't want in init (when your object isn't fully constructed yet).
Note: I'm talking about normal memory-management rules here. This is all different if you're using ARC. But I assume you would have mentioned if you were.

self.stack and stack are two completely different things. When you use stack, you are accessing an instance variable, not a property. This means that your accessor methods aren't called, which means automatic memory management isn't used. This is why you shouldn't release s in your example.
If you used self.stack instead, then you would be using a property. The compiler will treat self.stack = value exactly the same as [self setStack:value], and self.stack the same as [self stack]. Since accessors are being used, memory management will be taken care of to match the way you defined your property, and you should release a value after assigning it.

Maurício has the right answer: be sure to assign to the property to gain the benefits of #property. To clarify the point somewhat, try using code like this:
#interface StateStack : NSObject {
NSArray *_stack;
}
#property (nonatomic,retain) NSMutableArray *stack;
#end
#implementation StateStack
#synthesize stack=_stack;
#end
Now, if you try:
NSMutableArray* s = [[NSMutableArray alloc] init];
stack = s;
[s release];
You'll get an error, which will mean you tried to set the ivar rather than the property as intended. This mismatch between ivar name and property name is against Apple's recommendations, but it's a fine way to help you develop the habit of using property assignment when you intend to do so.

Related

Releasing synthesized properties in objective C

I'm a little confused about synthesized properties. I have an array that I want to be accessible from other classes so this is my code:
MyClass.h
#interface MyClass : CCLayer {
NSMutableArray *myArray;
}
#property (nonatomic, retain) NSMutableArray *myArray;
MyClass.m
#synthesize myArray;
-(id)init
{
myArray = [[NSMutableArray alloc] init];
}
-(void)dealloc
{
[myArray release];
myArray = nil;
}
I am a little confused now..is myArray the same as self.myArray? Do I have to release self.myArray as well? Thanks.
You declared your property as retain, it means that it will be retained automatically if you will set is using self.myArray. So, you can simply create autoreleased array in your init method and set it as
myArray = [NSMutableArray array];
self.myArray = myArray;
in this case you are not have to release it in the dealloc method or anything else. And as dasblinkenlight said you have to use #synthesize if you want to be sure that self.myArray is linked with your myArray instance.
Assuming that your #synthesize directive looks like this
#synthesize myArray;
you do not need to do anything in addition to what you are already doing: your property stores its value in the instance variable of the same name.
EDITED : Removed the alternative that suggests setting self.myArray in the dealloc method.
Yes you do, the best method is to set the property nil and release your variable.
-(void)dealloc{
self.myArray = nil;
[myArray release];
[super dealloc];
}
The code you provided is not really correct.
No, accessing a property and accessing the field itself are not the same.
My guess is that you are looking at old obj C examples where it was necessary to create the field with the property.
You also have no #synthesize directive in your code.
In current obj C code there is no need to declare a field to back the property, the field and the getter and setter will be autosynthesized (generated by the compiler) for you.
The default field generation is the name of your property with an underscore in front of it.
When you access the field directly via _myArray you will bypass any retain or release code that is contained in the generated getter/setter and have to manually manage memory in a non ARC project.
So to sum up, you dont need your field definition, and you dont need a synthesize directive.
You access your field directly with _myArray, or the property via self.myArray
They are not the same thing, one goes through generated code which obeys your property definition as to retain, assign, copy and accessing the field directly bypasses these semantics altogether.
If you define your property as retain you will need to release it in dealloc
You can use either
self.myArray = nil;
which will handle the release or
[_myArray release];
_myArray = nil;
Although someone in a previous post said setting the property to nil in dealloc might cause a problem Ive never seen it actually happen in my apps, ymmv
To answer your questions:
I am a little confused now..is myArray the same as self.myArray?
Yes, but no. Both point to the same object, the same area in memory. If you read myArray or self.myArray, they're identical in behavior minus the message send overhead for self.myArray.
However if you assign to myArray, the object will not be retained. It will only be retained if you assign to self.myArray.
Do I have to release self.myArray as well?
No.
You can also choose to either release or set the property to nil. As long as the property is #synthesize'd both examples do the same thing:
-(void) dealloc
{
[super dealloc];
[myArray release];
}
-(void) dealloc
{
[super dealloc];
self.myArray = nil;
}
See here for a discussion of the pros/cons to each approach.
From the question I think you're the developer who should really be using ARC. You'll have less to learn and fewer technical problems down the road. I can't understate how important using ARC is in these days, specifically if you don't have much ObjC experience. Read this how to enable ARC for cocos2d or just use Kobold2D to be able to work with an ARC-enabled cocos2d out of the box.

Acceptable ways to release a property

Assume there is a class with the following interface:
#import <Foundation/Foundation.h>
#interface MyClass : NSObject {
}
#property (nonatomic, retain) NSDate* myDate;
-(void)foo;
#end
and the following implementation:
#import "MyClass.h"
#implementation MyClass
#synthesize myDate = _myDate;
- (void)dealloc
{
[_myDate release];
[super dealloc];
}
-(void)foo
{
NSDate* temp = [[NSDate alloc] init];
self.myDate = temp;
[temp release];
}
#end
1) In the function foo will releasing like this ensure that the retain count of the objects is properly maintained (i.e. no memory is leaked and no unnecessary releases are performed).
NSDate* temp = [[NSDate alloc] init];
self.myDate = temp;
[temp release];
2) Same question as in 1) except applied to the following technique:
self.myDate = [[NSDate alloc] init];
[self.myDate release]
3) Same question as in 1) except applied to the following technique:
self.myDate = [[NSDate alloc] init] autorelease];
4) Same question as 1) but applied to the following technique:
self.myDate = [[NSDate alloc] init];
[_myDate release]
5) Same question as 1) but applied to the following technique:
[_myDate release];
_myDate = [[NSDate alloc] init];
1) Just fine.
2) Possibly unsafe, and will trigger warnings in the latest LLVM static analyzer. This is because the object returned by the getter method may not be the same one you passed to the setter. (The setter may have made a copy, for example, or may have failed validation and set a nil instead.) This would mean you were leaking the original object and over-releasing the one the getter gave back to you.
3) Just fine; similar to 1 but the release will come when the current autorelease pool is drained instead of immediately.
4) Possibly unsafe, but will not trigger warnings that I've seen. The issue is similar to the one described in 2; the object in the ivar may not be the one you passed to the setter.
5) Safe, but will not use the setter method or notify any observers of the property.
In the case where the property is a retain type, and both the getter and setter are just the synthesized versions, all of the above examples will work. However, they don't all represent best practice, and may trigger analysis warnings. The goal should be that the -foo method works correctly regardless of how myDate is managing its memory. Some of your examples above don't do that.
If, for example, you decided to change the property to copy later, you should not be required to change any other code to make it work correctly. In cases 2 and 4, you would be required to change additional code because the foo method is assuming that the setter will always succeed and always set the original object.
5) is a bug - it leaks the old instance as it doesn't get released but just reassigned.
1) is clean and the best way to go.
4) is ok but puts some burden on the memory system - the object might live longer than needed.
2) technically ok, but you shouldn't directly retain/release the property - that's what the syntactic sugar is for!
3) technically ok, but also bypasses the property and relies on implementation details.
2) and 3) are discouraged and ask for trouble in the future when some part of code changes.
Edit: New code doesn't leak in 5). It has the same downsides, though.
There's a reason why we got support for properties, and it does a great and consistent use. You should only consider bypassing them if your time profile gives very clear hints that this is a bottle neck (unlikely).
First, if you want to avoid the alloc, release, autorelease etc... you can call a date factory method which doesn't start with alloc.
For example:
self.myDate = [NSDate date];
The date class factory method does an autorelease according to the convention rules. Then the property retains it.
Alloc will give it a retain count of 1, then assigning the property will retain it. Since your class is now retaining it from the property, you can release it to counter act the alloc.
Ditto but that's a wierd round about way to do it.
3 is equivalent to the code I had above ([NSDate date]);
In this case, the property will retain it (after alloc incremented the retain count), then you're going under the covers to decrement it. Works but I wouldn't recommend doing that since you're synthesized (retain) property will do that for you.
the pattern of release and renew is merely a semantic. You get a retain count for each of the following.
myObject = [Object alloc]
objectCopy = [myObject copy]
myNewObject = [Object newObjectWithSomeProperties:#"Properties"] // Keyword here being new
// And of course
[myObject retain]
a property with the modifier (retain) or (copy) will have retain count on it.
the backing store _myDate is merely where the object is actually stored.
when you get a retain count you need to release.
Either immediately with the [myObject release] message or let the pool release it with [myObject autorelease]
Whatever the case, Any retain you are given (implicit or explicit) will need to be released. Otherewise the garbage collector will not collect your object and you will have a memory leak.
the most common usage in
Object myObject = [[[Object alloc] init] autorelease]; // Use this when you dont plan to keep the object.
Object myObject = [[Object alloc] init];
self.myProperty = [myObject autorelease]; // Exactally the same as the Previous. With autorelease
// Defined on the assignment line.
self.myProperty = [[[Object alloc] init] autorelease]; // Same as the last two. On one line.
I will demonstrate other possibilities
// Uncommon. Not incorrect. But Bad practice
myObject = [[Object alloc] init];
self.myProperty = myObject;
// Options
[_myProperty release] // Bad practice to release the instance variable
[self.myProperty release] // Better practice to Release the Property;
// releasing the property or the instance variable may not work either.
// If your property is using the (copy) modifier. The property is copied rather then retained.
// You are still given a retain count.
// But calling release on a copy will not release the original
[myObject release]; // Best Practice. Good when Threading may run the autorelease pool
[myObject autorelease]; // As good as the previous.
// But may leave your object in memory during long operations
Essentially, your object given a retain will be the same object in the Property the Variable and the Instance Variable. Releasing on any of them will release it.
However. Best practice says that if you retain an object. Best to call release on the same variable of that object. Even if Autorelease and retain is called on the other side.
// Other items that give you a retain count.
Core Media or Core Anything Functions that have Create Or Copy in the name.

Use autorelease when setting a retain property using dot syntax?

I see in some sample code that autorelease is used. I am not familiar with the instances when this is required. For example, if I create an annotation object
Header file
#interface someViewController: UIViewController
{
Annotation *annotation;
}
#property (nonatomic, retain) Annotation *annotation;
#end
Implementation file
#implementation someViewController
#synthesize annotation
#end
Question: Is it the correct approach if I initialize my annotation object in the implementation file like this?
self.annotation = [[Annotation alloc] initWithCoordinate:location];
Do I need to set autorelease for this? Or can I just do it the normal way and add the release in the dealloc method?
this is correct:
self.annotation = [[[Annotation alloc] initWithCoordinate:location] autorelease];
because annotation property is declared as a retain property, so assigning to it will increment its retain count.
you will also need, all the same, to release self.annotation in -dealloc.
in short:
init will set retain count to 1;
assigning to self.annotation, will set it to 2;
autorelease will set it back to 1 when the main loop is executed again;
release in dealloc will set the retain count to 0, so that the object will be deallocated);
the best way to think of autorelease is the following, in my opinion: autorelease will "schedule" an "automatic" release for your object at some (near) point in future (typically when the control flow goes back to the main loop, but details are hidden in the hands of Apple).
autorelease is mostly useful in conjunction with init, specifically in the following cases:
when you init a local variable, so that you don't have to release it explicitly before it goes out of scope (the main loop will do that for you);
when you return a pointer to an object you have just created without keeping ownership of it (typical case of the create/make* kind of selectors, the receiver is required to retain it to get ownership);
with properties that retain, when you assign to them an object that they should own uniquely;
with data structures that increment the retain count (NSMutableArray, NSMutableDictionary, etc): you should generally autorelease a newly inited object when you add it to such data structure.
apart from case 2, it is evident that the use of autorelease is meant to improve readability of the code and reduce the potential for errors (meaning that in all of the other cases, you could simply release explicitly your object after the assignment or at the end of the scope).
when using properties, you have always to check whether they are of the retain or assign/copy case; in the first case, assigning a newly inited object to a property generally requires autorelease.
Anyway, I would suggest at least skimming one of the many tutorial on memory management for iOS.
Autorelease is telling the object to release itself before leaving the scope.
Sometimes when you code, you'll encounter something like this
- (void)doSomething
{
if(true)
{
NSString *foo = [[NSString alloc] initWithString:#"foo"];
//Some execution here
[foo release];
}
}
- (void)doSomething
{
if(true)
{
//By doing this is telling to to release foo object before getting out of the scope
//which is similar with above practice
NSString *foo = [[[NSString alloc] initWithString:#"foo"] autorelease];
//Or you can do it this way
NSString *foo = [[NSString alloc] initWithString:#"foo"];
[foo autorelease];
//Some execution carry on, it'll release foo before entering next scope
}
//This is out of the scope
}
Of course, releasing an object doesn't mean deallocating the object.
Sometimes you retain the object so you can still use it outside of its scope.
Judging from your question, if your the object is located within your header file/interface.
You should release it in dealloc method. CMIIW.

ivars and how to properly instantiate their values (iPhone)

I have been developing an app for a while and now I have gotten to the "Instruments-Leaks" part.
I remember a thing that puzzled me about ivars a few months back when I was learning. I took the whole thing a bit on faith and just followed the way Apple and others did it. As far as I can read, the accessors generated by the SDK will take care of the memory management.
But how are ivars themselves initialized?
If I have an ivar like this in my interface;
#interface
{
NSArray *results;
}
#property(nonatomic, retain) NSArray *results;
#end
#implementation
#synthesize results;
If I during run time try to do this:
[self setResults:allReadyInitializedArray];
It will crash, telling me that this result object was not initialized. If I however do this:
self.results = [[NSArray alloc] init]; //Im assigning this property memory, but hasn't the SDK already done that?
[self setResults:allReadyInitializedArray];
it will work but it will apparently leak memory.
I was under the impression that using the generated
accessors would release the old value before setting the new, meaning
the above ought to come out with the old value released and the new with a +1 retain count.
Does it specifically have to do with the ivar being of type NSArray/NSMutableArray, I can't recall it has been a problem with other ivars.
The problem has been particular prominent in my XML parser, where I continuously need to set an ivar value, use it, overwrite this value, use the new value etc.
Would someone please help me outline the correct way "of going from": #property() -> #synthesize -> using the ivar -> to dealloc?
I have read the memory management documents, I have tried looking for some in debt documentation that was within my understanding, but it seems that even though I use ivars on a daily basis I don't understand what goes on behind the scenes.
All ivars initially set to nil so you need to instantiate them before use. It is really hard to say why setResults may produce errors without seeing its implementation.
self.results = [[NSArray alloc] init];
Here you create new array object using alloc method - its retain count equals 1. After that your setter method retains your array once more and so your 1st objects retain remains "unhandled" resulting in memory leak. To remove leak you can rewrite your code like:
self.results = [[[NSArray alloc] init] autorelease];
// or
self.results = [NSArray arrayWith...]; // any NSArray's convenience method that returns autoreleased object.
My understanding is that
self.results = anArray;
is the same as
[self setResults:anArray];
just because results is a property in this case.
The way setResults: is implemented is set by the #property (in this case it will retain the new value). So this means anArray will have a retain count of 1. After setting self.results, anArray will have a retain count of 2. This is why you want to release the previously used anArray.
That said, I don't understand why setResults: crashes when you're setting it. (Maybe it just crashes only when you try to use self.results, instead of setting it?)
I'm just a beginner myself, if something is wrong I strongly encourage everyone who reads this to let me know what is wrong or correct. Still learning this myself.
The way Apple would do this:
In the .h file
#property (nonatomic, retain) NSArray *results
In the .m file
#synthesize results;
- (id)init {
NSArray *anArray = [[NSArray alloc] init]; // retainCount = 1
self.results = anArray; // retainCount = 2
[anArray release]; // retainCount = 1, only one "left" is in self.results
}
- (void)dealloc {
[results release];
}

objective-c "mutating method sent to immutable object" error

I'm pretty new to objective-c and try to create a small app for the iphone.
I'm nearly done beside this little error here. Actually, I've searched hours with google to find a proper solution but unfortunately I'm not able to find a solution which works.
I'm using this tutorial here to build up an UITableView: UITableView Tutorial
The full error message looks like this:
* Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '* -[NSCFArray insertObject:atIndex:]: mutating method sent to immutable object'
This is the Data Controller Header:
MyLinksDataController.h
#interface MyLinksDataController : NSObject {
NSMutableArray *tableList; //<---important part
}
- (unsigned)countOfList;
- (id)objectInListAtIndex:(unsigned)theIndex;
- (void)addData:(NSString *)data; //<---important part
- (void)removeDataAtIndex:(unsigned)theIndex;
#property (nonatomic, copy, readwrite) NSMutableArray *tableList; //<---important part
.....
And the Data Controller Method:
MyLinksDataController.m
#import "MyLinksDataController.h"
#implementation MyLinksDataController
#synthesize tableList;
- (id)init {
if (self = [super init]) {
NSLog(#"Initilizing DataController");
//Instantiate list
NSMutableArray *localList = [[NSMutableArray alloc] init];
self.tableList = [localList copy];
[localList release];
//Add initial Data
[self addData:#"AAAAAAAAAAAAAA"];
[self addData:#"BBBBBBBBBBBBBB"];
}
return self;
}
-------------------------------later on in the source code---------------------------------
- (void)addData:(NSString*)data; {
[tableList addObject:data]; //<---- here the app crashes
}
I would pretty much appreciate any help.
Thank you for your support in advance.
Daniel
Sending the copy message to an NSMutableArray -- as in the following statement in init -- returns an immutable copy.
self.tableList = [localList copy];
Cocoa documentation uses the word immutable to refer to read-only, can't-be-changed-after-initialization objects. Hence the subsequenct call to addObject: fails with an error message.
Note how the assignment statement above doesn't trigger any compiler warning. copy returns an id, which fits comfortably -- as far as the compiler is concerned -- in the NSMutableArray* tableList. There's no runtime error here either, as no messages get passed around; an NSArray pointer is just placed in an NSMutableArray pointer variable.
To obtain a mutable copy, use mutableCopy instead.
Note that both copy and mutableCopy create a new array and copy the content of the original to it. A change in the copy will not be reflected in the original. If you just need another reference to the original array, use retain instead.
You can find more detail in the discussion section of the copyWithZone reference and in the NSMutableCopying protocol reference.
You're running into, basically, the memory management rules of Cocoa (specifically, these details). If there is an object with an immutable version and a mutable version, then sending -copy to an object will return an immutable object.
Let's step through the relevant part.
NSMutableArray *localList = [[NSMutableArray alloc] init];
This creates a new, empty mutable array that you own. Fine.
self.tableList = [localList copy];
This creates an immutable copy of the empty array. Furthermore, you own this freshly created copy. That's two objects you own at the moment.
This also assigns your copied object to the tableList property. Let's look at the property declaration:
#property (nonatomic, copy, readwrite) NSMutableArray *tableList;
This property is declared with the copy attribute, so whenever a new value is assigned to it, another -copy method is sent to it. This third copy, however, is not owned by you—it's owned by the object.
[localList release];
That releases the original empty mutable array. Fine, but there's still the one you made in the second line floating around, unreleased. That's a memory leak.
If you actually need a mutable copy of something, you want the -mutableCopy method. (The documentation for these methods is found under NSCopying and NSMutableCopying.) However, you're never going to get a mutable version of something into a property with the copy attribute, since it will send -copy to whatever it is assigned. Your property should use the retain attribute instead of the copy attribute, and the code to initialize it should look something like this:
NSMutableArray *localList = [[NSMutableArray alloc] init];
self.tableList = localList;
[localList release];
Or, a shorter version:
self.tableList = [NSMutableArray array];
There's no need to copy anything in this situation, you're just creating a fresh object.
If u are assigning localList from another object may be that is not Mutable in that case it can through this kind of error.
I hope it will be helpful.
self.tableList = [localList mutableCopy];
Hi instead of mutableCopy i believe "strong" can also be used to tackle this problem. I had similar problem in my code as well because of using "copy" instead of "strong." So the below line:
#property (copy, nonatomic) NSMutableArray *computers;
It should be:
#property (strong, nonatomic) NSMutableArray *computers;
Hope it will be of immense help for beginners making mistakes like me.
This will resolve the issue:
NSMutableArray *localList = [[NSMutableArray alloc] init];
self.localList = [[NSMutableArray alloc]initWithArray:localList];