This is what Instruments is pointing to.
students = [[NSMutableArray alloc] initWithArray:[course.students allObjects]];
I'm releasing the array in dealloc. In the rest of my code I'm only calling the array and I'm not alloc'ing it again. I've also tried filling the array via fast enumeration and I get the same problem.
Just to be sure, add an autorelease to it, like
students = [[[NSMutableArray alloc] initWithArray:[course.students allObjects]] autorelease];
Then see what happens. (maybe assign it to self.students btw, and make that a retained property using #property (nonatomic,retain))
Related
So assume I declared an object and created a retained property for it which is synthesized. So something like that in the header file:
NSArray *array;
#property (retain)....
After it is synthesized, I called release in the dealloc.
Now in the init method, if I want to also dynamically allocate that array, what do I do in terms of releasing it? So:
array = [[NSArray alloc] initWithObjects...
How do I keep the object retained as long as the class is running without leaking?
Thank you
self.array = [[[NSArray alloc] initWithObjects:...] autorelease];
or
NSArray *newArray = [[NSArray alloc] initWithObjects:...];
self.array = newArray;
[newArray release];
With both options, you additionally have to call [array release]; in dealloc.
By using its setter method, you normally don't have do worry about retains and releases.
All the init* (init, initWith..., etc.) methods return retained objects. The convenience constructors provided by some classes, on the other hand, provide objects that are not retained - or rather, retained, then autoreleased.
More here.
So you are doing the right thing by assigning a retained object to your ivar in the init method, then releasing it in dealloc.
For the rest of the object's life cycle, it would be smart to only use the synthesized accessors, as they take care of retaining and releasing.
All in all, you're good.
In order to take advantage of the goodness of properties, you need to prefix the variable name with self.
array = [[NSArray alloc] initWithObjects:...];
is not the same as
self.array = [[[NSArray alloc] initWithObjects:...] autorelease];
The former will assign the array directly to the instance variable. The latter will invoke the synthesized setArray method, which gives you retain/release for free. This will be useful should you decide to assign a new reference to array at any other point in time in the lifecycle of your class.
I have a property in my class, which is an NSArray. I am retaining the property.
My question is, what is the proper way to add objects to that array without leaking and making the retain count too high?
This is what I am using:
.h:
NSArray *foodLocations;
#property (nonatomic, retain) NSArray *foodLocations;
// I make sure to synthesize and release the property in my dealloc.
.m
- (void)viewDidLoad {
[super viewDidLoad];
NSArray *tempFood = [[NSArray alloc] initWithArray:[self returnOtherArray]];
self.foodLocations = tempFood;
[tempFood release];
}
Is this the correct way to do it?
Yes this is correct and my preferred way of doing it as it renders the code more readable.
You are essentially allocating a temporary array and then assigning it to your property with a retain attribute, so it is safe to dealloc it as your property now "owns" it. Just remember that you still need to release it in your dealloc method.
You could also initialise the array and assign it to the property in the view controllers init method, depending on whether you need the property to be available to you before the view actually loads (i.e. in case you want to read the value of the property before pushing the view controller etc...)
you will typically want to declare the property copy in this case.
in most cases, immutable collection accessors should be copy, not retain. a lot of people get this wrong, and end up writing a lot of copying manually and sharing objects which should not be shared, thinking they are doing themselves good by cutting a corner.
copying in this form (the collection) is shallow. the objects in the array are not copied, just the array's allocation.
a good implementation of an immutable collection can simply implement copy by retaining self. if the argument is mutable, you want a copy anyhow (in the majority of cases).
your program is then simplified to a declaration of:
// note: copy, not retain. honor this if you implement the accessors.
#property (nonatomic, copy) NSArray * foodLocations;
and then the setter:
self.foodLocations = [self returnOtherArray];
of course, you must still init, dealloc, and handle thread-safety appropriately.
good luck
That looks fine. You don't actually need the tempFood variable, you can just do:
self.foodLocations = [[NSArray alloc] initWithArray:[self returnOtherArray]];
[self.foodLocations release];
or:
self.foodLocations = [[[NSArray alloc] initWithArray:[self returnOtherArray]] autorelease];
Or:
#synthesize foodLocations=_foodLocations;
then in code
_foodLocations = [[NSArray alloc] initWithArray:someOtherArray];
This avoids the autorelease required by
self.foodLocations = [[[NSArray alloc] initWithArray:someOtherArray] autorelease];
Yes, that is correct. Also good to keep in mind is what #synthesize is, in effect, doing for you. A synthesized (& retained) setter is functionally equivalent to the following code:
- (void)setVar:(id)_var {
[_var retain];
[var release];
var = _var;
[var retain];
[_var release];
}
So, basically, every time you call self.var = foo, it releases the previously stored value and retains the new one. You handle the reference counting in your code, and the setter handles its own.
I have an NSMutableArray I'm trying to reload after an async call. The first time it loads like this:
self.sessionProcList = [NSMutableArray arrayWithArray:[result records]];
After the user does some interaction, the same line will be reached to reload the NSMutableArray. This causes the crash
Header file has:
#interface...
NSMutableArray *sessionProcList;
... }
#property (nonatomic, retain) NSMutableArray *sessionProcList;
Say you do:
NSMutableArray *a = [NSMutableArray arrayWithObject: [[NSObject alloc] init]];
NSObject *o = [a objectAtIndex: 0];
[a removeAllObjects];
[o description]; // *BOOM*
The above will [generally -- sometimes not but only by coincidence] crash because o has been deallocated by the time the description method is invoked.
If you have a reference to an object in an array, but have not retained said reference, then said object may be deallocated out from under you when you empty the array.
(And nonatomic vs. atomic is irrelevant.)
If I had to guess, I would say that elements in that array are being referenced from somewhere else. Resetting the array causes the items using the references to crash.
I would check your application for other variables, properties, or UI elements using those variables that have not been release before resetting it.
Because arrayWithArray is a convenience method it gets initialised with an autorelease flag.
You haven't mentioned what the crash / error message is but I am guessing your NSMutableArray is getting released before your second iteraction with it starts.
Try and retain the array for however long you need it with:
self.sessionProcList = [NSMutableArray arrayWithArray:[result records]];
[sessionProcList retain];
And then release it when you're done with it:
[sessionProcList release];
I hope it helps.
Rog
I have a mutableArray that I fill up with objects. When I try to refill the array, I first use removeAllObjects - which produces a memory leak...
The properties of the object are synthesized, retained and released on dealloc.
The Array is initialized on viewDidLoad like this:
theArray = [[NSMutableArray alloc] initWithCapacity:10];
... and it's retained and synthesized. (#property (nonatomic, retain) NSMutableArray *theArray)
I'm adding the objects in a while-loop like this:
myObject *theObject = [[myObject alloc] init];
theObject.someProperty = #"theprop";
[theArray addObject: theObject];
[theObject release];
then on the next call of the method, I remove all objects like this:
[theArray removeAllObjects];
That's where the leak occurs. If I comment this line out, the leak doesn't appear. So I guess I'm doing something wrong in my object?
Seems like the problem is solved...
a) I didn't realize, that when I use instruments, the app isn't compiled before launch - thus, some of the changes I made were not taking into effect, when using instruments. So now I first build and run after a change and then run it in instruments.
b) thus, I don't really know what solved the problem. But it might be that I had the dealloc-method in my object wrong.
I was using:
[super dealloc];
[myProperty release];
instead of the other way around:
[myProperty release];
[super dealloc];
Thanks for the help, though!
Does myObject have any retained properties? If so, are you setting them to nil in the dealloc message? If not, when it is dealloced it won't release the objects that its properties are set to.
I'm getting this error when trying to see the contents of a NSMutableArray:
Program received signal EXC_BAD_ACCESS, Could not access memory.
Reason: KERN_PROTECTION_FAILURE at address: 0x00000021
0x94d5a688 in objc_msgSend ()
ViewController.h:
#interface PeopleViewController : UITableViewController {
NSMutableArray *people;
}
#property (nonatomic, retain) NSMutableArray *people;
ViewController.m:
#implementation PeopleViewController
#synthesize people;
In viewDidLoad:
- (void)viewDidLoad {
[super viewDidLoad];
// initialize our people array with an autoreleased object
people = [NSMutableArray array];
... Populate the people array with Person objects.
}
When I'm at the point where I'm modifying the contents of a cell in the tableview, I'm unable to access the people array in gdb when typing 'po self.people':
Person *person = [[Person alloc] init];
person = [self.people objectAtIndex: indexPath.row]; // <--- 'po self.people' called
cell.textLabel.text = person.personName;
Any ideas why I can't access it?
The line
people = [NSMutableArray array];
returns an autoreleased array that will be released on the next iteration of the current run loop. You should retain that:
people = [[NSMutableArray array] retain];
and of course release it in your dealloc method.
However: Apple engineers have often mentioned in conferences to avoid autoreleased instances like this whenever possible in the iPhone, for performance reasons. Try using alloc/init instead:
people = [[NSMutableArray alloc] initWithCapacity:1];
with the corresponding release in the dealloc method. In this case you don't even need to retain (init returns an instance with a retain count of 1, which is what you need).
And justin's comment is correct: you should do this instead:
Person *person = [people objectAtIndex:indexPath.row];
cell.textLabel.text = person.personName;
and this should work.
is indexPath.row > [people count]?
Also, why are you doing this:
Person *person = [[Person alloc] init]
You're allocating memory, and then pointing to completely different memory.
You can avoid having to fuss with retaining properties by using the self notation to call the accessor and setter methods created by the #synthesize directive.
When you set the people property directly in viewDidLoad it sets the property but does nothing for memory management. However, if you set it with self.people you actually call the synthesized setter method that because of the retain setting of the #property directive will automatically retain the assigned array.
As an aside, I would recommend always using -[NSMutableArray initWithCapacity:] instead of a bare init. It is the actual initializer for the class. You can call it with just '1' if you don't know how big it will be. In the past, I have seen odd problem arise from just using bare init.