Message sent to deallocated instance which has never been released - iphone

I started dealing with NSOperations and (as usual with concurrency) I'm observing strange behaviour.
In my class I've got an instance variable:
NSMutableArray *postResultsArray;
when one button in the UI is pressed I initialize the array:
postResultsArray = [NSMutableArray array];
and setup the operations (together with dependencies).
In the operations I create a custom object and try to add to the array:
PostResult *result = [[PostResult alloc] initWithServiceName:#"Sth" andResult:someResult];
[self.postResultsArray addObject:result];
and while adding I get:
-[CFArray retain]: message sent to deallocated instance 0x3b40c30
which is strange as I don't release the array anywhere in my code (I did, but when the problem started to appear I commented all the release operations to be sure that they are not the case). I also used to have #synchronized section like below:
PostResult *result = [[PostResult alloc] initWithServiceName:#"Sth" andResult:someResult];
#synchronized (self.postResultsArray) {
[self.postResultsArray addObject:result];
}
but the problem was the same (however, the error was for the synchronized operation).
Any ideas what I may be doing wrong?

postResultsArray = [NSMutableArray array];
[NSMutableArray array] is a convient method which is equivalent to [[[NSMutableArray alloc] init] autorelease]. So there is an implicit (auto)release there. Since you're going to keep it, you have to use one of these 3 changes:
postResultsArray = [[NSMutableArray array] retain];
postResultsArray = [[NSMutableArray alloc] init];
Exploit the fact that a setter should retain the new value (if you declare as #property(retain)):
self.postResultsArray = [NSMutableArray array];

Related

Memory leaks Problem in iPhone?

I want to get some memory leaks in my code, how can i fix the memory leak.
dashboard = [[NSMutableArray alloc] init];
[dashboard addObject:[[NSDictionary alloc] initWithObjectsAndKeys:#"demo_1.jpg",#"pic_source",#" Head",#"Title",nil]; // memory leaks here.
if ( theConnection ) {
receiveData = [[NSMutableData data] retain]; //memory leaks here.
}
But i have released dealloc - in[receiveData release];, but memory leaks happened. I know the retain, the count is increased, but how can i released the data properly.
Thanks!
i think your leak in the line:
[dashboard addObject:[[NSDictionary alloc] initWithObjectsAndKeys:#"demo_1.jpg",#"pic_source",#" Head",#"Title",nil];
just change it to
[dashboard addObject:[NSDictionary dictionaryWithObjectsAndKeys:#"demo_1.jpg",#"pic_source",#" Head",#"Title",nil];
addObject retains the object so you can use convenience creation methods which autorelease the object they create.
and another possible leak... if you define your receiveData as a property with retain attribute you don't need to call retain explicitely. You can call self.recieveData = [NSMutableData data]. This will retain it. Of course you will still need to release it in dealloc.
EDIT to show the code:
NSMutableArray *anArray = [[[NSMutableArray alloc] init] autorelease];
[sections setValue:anArray forKey:display_date];
dashboard addObject:[[NSDictionary alloc] initWithObjectsAndKeys:#"demo_1.jpg",#"pic_source",#" Head",#"Title",nil];
You've called init method - then you are the owner of an object. When you've put it to the array - the retain was called too. Just call autorelease to fix the leak.
receiveData = [[NSMutableData data] retain]; - if you will call release this object will be deleted when out of scope. If you will write
receiveData = [NSMutableData data];
It will be automatically deleted when out of scope
EDIT
If you are using methods with init word in them then you are the owner of such objects and they will not be deleted automatically until you'll call release method on them. If you don't want to own the object create it with some static method. For example:
NSMutableArray *array = [NSMutableArray arrayWithObjects: ... , nil];
It's the same as calling
NSMutableArray *array = [[[NSMutableArray alloc] initWithObjects: ... , nil] autorelease];
Autorelease means the object will receive a release method when out of scope - and if it was not retained will be deleted automatically

memory leak situation in iphone

I have a memory leak when i call a method that return me a string----
the method definition is as follows
-(NSMutableArray *)read
{
NSMutableArray *dataArray = [[NSMutableArray alloc] init];
//picking data from database here
return dataArray;
}
this show a big memory leak
i also tried--- NSMutableArray *dataArray = [[[NSMutableArray alloc] init]autorelease];
but this time leack checking process gets hanged
i also cannot release that array before return
please help
-(NSMutableArray *)read
{
NSMutableArray *dataArray = [[NSMutableArray alloc] init];
//picking data from database here
return dataArray;
}
Anything that uses the method read will expect to get back an object it does not own. However, as written here, dataArray is still owned at the point of return. You can't release it because that might make it go away altogether. You must, in this instance autorelease the array. You can either do this:
-(NSMutableArray *)read
{
NSMutableArray *dataArray = [[[NSMutableArray alloc] init] autorelease];
//picking data from database here
return dataArray;
}
or this
-(NSMutableArray *)read
{
NSMutableArray *dataArray = [[NSMutableArray alloc] init];
//picking data from database here
return [dataArray autorelease];
}
You say "leak checking process get hanged" but I'm really not sure what you mean by that. Whether it hangs, crashes or plays the Botswana National Anthem, you definitely need to autorelease the returned array and any other problem is actually a different problem. Possibly, you are forgetting to retain the data elsewhere.
Another answer more...
There are many conventions in cocoa/cocoa-touch, there is one of them that says that if a method has the prefix init then you will have the ownership of that object (hence you have to release it)
This is NOT your case, hence if you do:
DatabaseReader *dbReader = [[DatabaseReader alloc] init];
NSMutableArray *mutArray = [dbReader read];
[dbReader release];
you are NOT supposed to release mutArray. BUT, the object created HAS to be released by someone. So you can do as JeremyP wrote. alloc/init and put it into a autorelease pool inside read method implementation. Or, you can do:
-(NSMutableArray *)read
{
NSMutableArray *dataArray = [NSMutableArray array];
//IMPORTANT:
//Did you noticed that I am not using any method
//with init prefix for the creation of dataArray ?
//so I don't need to release by my self ;)
//picking data from database here
return dataArray;
}
Which is basically the same. ;)
Ownership of the returned object may be returned to the object that receives from this function. You may do some debugging with the object's retain count using something like this...
NSLog(#"Retain count: %i", [dataArray retainCount]);
Turn on the debugging console (Command + R in Xcode) to see the NSLog output.

Why Instruments report a leak?

I am developing an iphone app. Instruments reported a leaked object ServiceTypes. Below is the relevant code. Does anyone have any ideas? Thanks a lot for your help.
ServiceTypes *serviceTypes = [[ServiceTypes alloc] init];
if ([userConnection getServiceTypes:serviceTypes]) {
if ([serviceTypes.types length] > 0) {
NSArray *array = [[NSArray alloc] initWithArray:[serviceTypes.types componentsSeparatedByString: SERVICE_TYPE_DELIMITOR]];
serviceRequestTypes = [[NSMutableArray alloc] initWithArray:array];
[array release];
}
}
[[self typesTableView] reloadData];
[serviceTypes release];
It doesn't look like serviceTypes is being leaked. From the code you posted, serviceTypes is always released at the end of the method, and it doesn't appear to be retained anywhere in your sample. My question is: what happens inside getServiceTypes:. Does that method retain the serviceTypes parameter?
One more thing. If serviceRequestTypes is an instance variable (and it looks like it is), then you may be leaking memory by reassigning it without releasing the existing serviceRequestTypes object first. You should either rewrite serviceRequestTypes to be a property and use a synthesized accessor or make sure to release it every time before assigning. If its current value is nil, no big deal; the release message will simply be ignored. For example:
[serviceRequestTypes release];
serviceRequestTypes = [[NSMutableArray alloc] initWithArray:[serviceTypes.types componentsSeparatedByString:SERVICE_TYPE_DELIMITER]];

Building an array of arrays

I am trying to get the following loop working to fill an array of arrays:
while (condition) {
[itemsArray fillFromDB];
if (! [checkArray containsObject:checkFlag]) {
// Add existing itemsArray to myArray
if (itemsArray.count) {
// add the itemsArray to myArray and create a new instance of itemsArray
[myArray addObject:itemsArray];
[itemsArray release];
NSMutableArray *itemsArray = [[NSMutableArray alloc] init];
}
[itemsArray addObject:myObject];
[checkArray addObject:checkFlag];
} else {
[itemsArray addObject:tmpEvent];
} }
However I try to shape this loop it falls over the release of itemsArray
when I use release (as above), the array does not re-initialise as a new instance with alloc. Whilst expecting emptyness, the next Object is added to the old array.
when I use removeAllObjects, my Array is emptied and so is the array attached to myArray.
Where am I going in the wrong direction?
You might place:
itemsArray = nil;
after the release message, to ensure that you're not pointing to an old instance.
EDIT
Looking at this again, you have:
NSMutableArray *itemsArray = [[NSMutableArray alloc] init];
This is scoped within the if statement.
So take out NSMutableArray and just use:
itemsArray = [[NSMutableArray alloc] init];
Don't write NSMutableArray *itemsArray = [[NSMutableArray alloc] init];--you're re-declaring the variable in the scope of the if statement, so outside the if statement, itemsArray will still refer to the old value (I'm not sure why the compiler isn't complaining). You can just say itemsArray = [[NSMutableArray alloc] init] instead.
You also might want to use autorelease, to simplify, as well.
The others have found the problem, but have created a new problem. The first time you create the mutable array, you need to use NSMutableArray *itemsArray = [[NSMutableArray alloc] init];. Then, after, you can release and use itemsArray = [[NSMutableArray alloc] init];. It is important that the first one (the one that creates the pointer) occurs only once, and the rest can occur as many times as desired.
EDIT:
You could write NSMutableArray *itemsArray; before the if statement, and then use itemsArray = [[NSMutableArray alloc] init]; in the if statement.

[CFArray release]: message sent to deallocated instance

I'm using the following method in my code:
- (NSMutableArray *) newOrderedArray:(NSMutableArray *)array ByKey:(NSString *)key ascending:(BOOL)ascending {
NSSortDescriptor *idDescriptor = [[NSSortDescriptor alloc] initWithKey:key ascending:ascending];
NSArray *sortDescriptors = [NSArray arrayWithObject:idDescriptor];
NSArray *orderArray = [array sortedArrayUsingDescriptors:sortDescriptors];
[idDescriptor release];
NSMutableArray *result = [NSMutableArray arrayWithArray:orderArray];
return result;
}
Is this a well-coded convenience method? As I think, it returns an autoreleased NSMutableArray.
This method is called by another one:
- (id) otherMethod {
NSMutableArray *otherResult = [[[NSMutableArray alloc] initWithCapacity:[otherArray count]] autorelease];
// I add some stuff to otherResult and then...
NSMutableArray *result = [dbUtils newOrderedArray:otherResult ByKey:#"objectId" ascending:NO];
return result;
}
This method (otherMethod) is called in some view controller where I want to store returned array and release it when deallocating the view controller. However, when [result retain] is called in this view controller (because I need it to be available and I can't allow it to be deallocated) I receive the following error:
[CFArray release]: message sent to deallocated instance
I've tried to log [result retainCount] just before calling retain and it print "1". I don't understand why an error is thrown when calling retain.
Thank you,
A
I don't see anything technically wrong with the code above--otherMethod should return an autoreleased NSMutableArray. Are you sure you're getting the error when calling retain? It looks more like you might be accidentally be sending release at some point instead of retain.
Stylistically, there's one thing--methods with "new" in the title should always return non-autoreleased objects, so you should either name your method something else (such as orderedArray...) or use [[NSMutableArray alloc] initWithArray:] instead of arrayWithArray. Also, method signatures shouldn't start with a capital (so ByKey should be byKey.
try this:
NSMutableArray *otherResult = [[NSMutableArray initWithCapacity:[otherArray count]];
Because initWithCapacity will return an autoreleased Array. Right now you tell the Autoreleasepool to release the Array twice.
initWithCapacity:does not return an autoreleased object. – Wevah
AFAIK initWithCapacity is a convenience initializier, which by convention return autoreleased objects. So if the object is only used within a local method, the autoreleasepool should deallocate it. Care to elaborate?