I am using a dictionary with parameters to send to a web service. I keep getting memory leaks from it, altho I do a release for the object. My code:
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
// getting an NSString
NSString *clientID = [prefs stringForKey:#"ClientID"];
//Call web service
id delegate1 = self;
AsyncWebServiceController * webService = [[[AsyncWebServiceController alloc] initWithDelegate:delegate1
selSucceeded:#selector(webServiceConnectionSucceeded:)
selFailed:#selector(webServiceconnectionFailed:)] autorelease];
NSMutableDictionary *params = [[NSMutableDictionary alloc] init]; //Memory leak here
[params setValue:clientID forKey:#"clientId"]; //Memory leak here
[params setValue:[self.jobDetails objectForKey:#"BoardId"] forKey:#"jobBoardId"];
[params setValue:[self.jobDetails objectForKey:#"Id"] forKey:#"jobId"];
[webService startRequest:#"JobReviewGet" parameters:params];
[params release];
Any ideas? Thanks!!
Build with analyze. That may give some pointers.
Outside of that:
You are calling alloc on AsyncWebServiceController do you own it but the code above does not release.
You should be calling setObject:forKey instead of setValue:ForKey. setValue is for KVC.
You should be using :
- (void)setObject:(id)anObject forKey:(id)aKey;
Thus you code should look like:"
NSMutableDictionary *params =
[[NSMutableDictionary alloc] init]; //Memory leak here
[params setObject:clientID forKey:#"clientId"]; //Memory leak here
[params setObject:[self.jobDetails objectForKey:#"BoardId"] forKey:#"jobBoardId"];
[params setObject:[self.jobDetails objectForKey:#"Id"] forKey:#"jobId"];
[webService startRequest:#"JobReviewGet" parameters:params];
[params release];
What does [webService startRequest:#"JobReviewGet" parameters:params]; method do with the param, does it retain it? If so you also need to release it there.
Also ar some point you will need to release the webService.
Why don't you use the convenience constructor?
NSMutableDictionary *params = [NSMutableDictionary dictionary];
Then there would be no need to release it. This should solve your problem.
Are you releasing your webService object at some point? Also is the delegate of AsyncWebServiceController an assigned or retained property? Delegates should generally be assigned properties to avoid retain loops.
Related
I have coded this method in a class:
- (NSMutableDictionary *)fetch {
NSMutableDictionary *ret = [[NSMutableDictionary alloc] init];
// filling ret with some data here
return ret;
}
Is the way of returning this NSMUtableDictionary object without release correct ?
Thx for helping,
Stephane
Do the following:
- (NSMutableDictionary *)fetch {
NSMutableDictionary *ret = [[NSMutableDictionary alloc] init];
// filling ret with some data here
return [ret autorelease];
}
To learn more about autoreleaseing, read this Apple document called Memory Management Programming Guide.
use like this
- (NSMutableDictionary *)fetch {
NSMutableDictionary *ret = [[NSMutableDictionary alloc] init];
// filling ret with some data here
return [ret autorelease];
}
Developer Docs
Auto release puts the object into a autorelease pool and release is called later after it has been returned.
I implement a method to return a dictionary in my app. But I find a memory leak using instrument, I tried to figure it out, but I still cannot find it. Can anyone help me out?
Thanks in advance, here is the code for that methods:
-(NSMutableDictionary *)initDict
{
NSMutableDictionary *dict = [[NSMutableDictionary alloc]init];
[dict setObject:self.name forKey:#"Name"];
//Some similar set object for key here...
return dict;
}
I think the problem is from allocing memory for dict and not releasing it. But in the method, it seems I cannot release dict. So is there any method to fix the leak?
All variants are good. Here is third variant (choose wisely):
Replace
NSMutableDictionary *dict = [[NSMutableDictionary alloc]init];
with
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
I think you just need to change the last line of initDict to this:
return [dict autorelease];
When you are creating any object in your function and you want to return them then you should always create it in a way that those objects are autoreleased. So you should change your code like below.
NSMutableDictionary *dict = [[[NSMutableDictionary alloc]init]autorelease];
So whenever you create any object just call autorelease method on that.
I have a method like this
- (NSDictionary *)getCellValuesForRow:(int)row {
NSMutableDictionary *dictValues= [[NSMutableDictionary alloc] init];
Outage *outage = [listOutage objectAtIndex:row];
[dictValues setObject:outage.duration forKey:#"OutageDuration"];
return dictValues;
}
and this value is stored in this way
NSDictionary *dict = [[NSDictionary alloc] initWithDictionary:[self getCellValuesForRow:(indexPath.row-1)]];
how to release memory in this scenario
This is what autorelease is for.
NSMutableDictionary *dictValues= [[[NSMutableDictionary alloc] init] autorelease];
You should autorelease dictValues in getCellValuesForRow, or just don't alloc it. This will keep it autoreleased:
NSMutableDictionary *dictValues= [NSMutableDictionary dictionary];
In most cases it should be the responsibility of whatever calls it to alloc it (if it needs to be kept around after the autorelease pool is cleared), then dealloc it later.
If whatever calls it doesn't need it kept around, it can just leave it autoreleased.
An alternative is to simply use
NSMutableDictionary *dictValues= [NSMutableDictionary dictionary];
That's effectively the same thing as what Dan suggested. Just less typing.
It applies to your next line, too:
NSDictionary *dict = [NSDictionary dictionaryWithDictionary:[self getCellValuesForRow:(indexPath.row-1)];
I've got a thread (specifically an NSOperation) that runs to load some images for me for a scroll view when my main view asks for them. Any number of these NSOperations can be queued at once. So it goes with the filepath I give it and loads the image from the disk (as UIImages) and then sends the object back to my mainview by using performSelectorOnMainThread: and passing my mainview an NSDictionary of the object, and an image ID value. My main view is then supposed to insert the image object and the image ID string into an NSMutableDictionary that it has for the mainview to be able to use. I've verified that the NSMutableDictionary is allocated and initialized fine, but when the method the NSOperation calls tries to add the objects to the dictionary nothing happens. I've verified that the object and string i get from the dictionary the thread sent me are not null or anything but yet it doesn't work. Am I not doing something right or using a bad technique? What would anyone suggest to do in a situation like this where I need to add UIImages to an NSMutableDictionary from a thread? Thanks so much!
Here's the NSOperation code I use:
- (void)main {
NSString *filePath = [applicaitonAPI getFilePathForCachedImageWithID:imageID andSize:imageSize];
UIImage *returnImage = [[UIImage alloc] initWithContentsOfFile:filePath];
if (returnImage) {
NSMutableDictionary *dict = [[NSMutableDictionary alloc] initWithCapacity:2];
[dict setObject:returnImage forKey:#"IMAGE"];
[dict setValue:[NSString stringWithFormat:#"%d", imageID] forKey:#"IMAGE_ID"];
NSDictionary *returnDict = [[NSDictionary alloc] initWithDictionary:dict];
[dict release];
[mainViewController performSelectorOnMainThread:#selector(imageLoaderLoadedImage:) withObject:returnDict waitUntilDone:NO];
[returnDict release];
}
}
And here's the method on the main thread:
- (void)imageLoaderLoadedImage:(NSDictionary *)dict {
UIImage *loadedImage = [dict objectForKey:#"IMAGE"];
NSString *loadedImage = [dict valueForKey:#"IMAGE_ID"];
[imagesInMemoryDictionary setObject:loadedImage forKey:loadedImageID];
[self drawItemsToScrollView];
}
[mainViewController performSelectorOnMainThread:#selector(imageLoaderLoadedImage:) withObject:nil waitUntilDone:NO];
You're not passing returnDict as the parameter to the method. You're passing nil.
A couple of other thoughts:
you don't need to create returnDict. You can just use dict as the method parameter.
you're leaking returnImage.
edit
Since you apparently are passing returnDict as the parameter to the method, my other guess would be that mainViewController is nil. Other than that, your code looks functional.
I have been living on Instruments for last few hours staring at a puzzling memory leak. I have isolated it to this single line of code in an NSOperation subclass I wrote:
NSData *myData = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:myURLString]];
Periodically this will leak 3500 bytes. Is anyone else seeing this? If so, is there a work around?
Thanks in advance.
UPDATE:
Here is the relevant section of code within the main() body of my NSOperation subclass:
- (void)main {
// ...
NSData *sequenceData =
[[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:concatenatedURLString]];
NSString *sequenceString =
[[NSString alloc] initWithBytes:[sequenceData bytes] length:[sequenceData length] encoding:NSUTF8StringEncoding];
NSDictionary *result = [NSDictionary dictionaryWithObjectsAndKeys:
self.chromosome, #"chromosome",
[NSNumber numberWithInt:self.basepairStart], #"basepairStart",
[NSNumber numberWithInt:self.basepairEnd], #"basepairEnd",
sequenceData, #"sequenceData",
sequenceString, #"sequenceString",
nil];
[sequenceData release];
[sequenceString release];
[self.target performSelectorOnMainThread:self.action withObject:result waitUntilDone:NO];
}
As you can see sequenceData and sequenceString are properly released. Also, I have confirmed that all ivars of this subclass (chromosome. etc.) are properly memory managed.
-Doug
You have to release or autorelease myData, otherwise it will leak according to the Cocoa Memory Management Rules