NSTimeInterval memory leak - iphone

I have a weird memory leak with NSTimeIntervall and NSDate. Here is my code:
NSTimeInterval interval = 60*60*[[[Config alloc] getCacheLifetime] integerValue];
NSDate *maxCacheAge = [[NSDate alloc] initWithTimeIntervalSinceNow:-interval];
if ([date compare:maxCacheAge] == NSOrderedDescending) {
return YES;
} else {
return NO;
}
date is just an NSDate object, this should be fine. Instruments tells me that "interval" leaks, yet I do not quite understand this, how can I release a non-object? The function ends after the code snippet I posted here, so from my understanding interval should get automatically deallocated then.
Thanks a lot!

It is probably telling you that a leak is happening on that line.
The expression [[[Config alloc] getCacheLifetime] integerValue] is your problem.
First of all, you care creating an object (calling alloc) but you lose the reference to it before calling release or autorelease, so it is leaking.
Also, you really ought to call an init method immediately after allocating the object. Even if your Config class doesn't do anything special, NSObject's init method will need to be called.
If you replace that line with
Config *config = [[Config alloc] init];
NSTimeInterval interval = 60*60*[[config getCacheLifetime] integerValue];
[config release];
That leak should be plugged up.
You are also leaking the maxCacheAge object. Inserting [maxCacheAge autorelease]; before the if statement should fix that.

Found the problem, in case you come across the same issue, this is the solution:
[[ClubzoneConfig alloc] loadConfigFile];
NSTimeInterval interval = 60*60*[[[ClubzoneConfig alloc] getCacheLifetime] integerValue];
NSDate *maxCacheAge = [[NSDate alloc] initWithTimeIntervalSinceNow:-interval];
if ([date compare:maxCacheAge] == NSOrderedDescending) {
[maxCacheAge release];
return YES;
} else {
[maxCacheAge release];
return NO;
}
The problem is that the maxCacheAge object needs to get released, as I own it (see link below).
I got it thanks to the awesome solution here: iPhone Memory Management

Related

Why does this Code cause the EXC_BAD_ACCESS error?

Here's a piece of code I wrote for cleaning A string of unwanted chars and double spacing.
However, I seem to have misunderstood memory management somewhere and it keeps causing the EXC_BAD_ACCESS error. The Code works fine functionally when the release statements are removed but that would cause memory leaks.
-(NSString*) cleaningString:(NSString*) input {
NSCharacterSet* wantedCharacters=[[NSCharacterSet alloc] init];
wantedCharacters=[ NSCharacterSet
characterSetWithCharactersInString:#"qwertyuiopasdfghjklzxcvbnm"];
NSString* cleanStringOutput=[[NSString alloc] initWithString:#""];
NSString* currentLetter =[[NSString alloc] initWithString:#" "];
NSRange unwantedCharacters=[currentLetter rangeOfCharacterFromSet:wantedCharacters];
for (int i=0; i<input.length; i++) {
currentLetter=[NSString stringWithFormat:#"%c",[input characterAtIndex:i]];
unwantedCharacters=[currentLetter rangeOfCharacterFromSet:wantedCharacters];
doubleSpace=YES;
if (i<input.length-1) {
if (([currentLetter isEqualToString:#" "])&&([[NSString stringWithFormat:#"%c",[input characterAtIndex:i+1]] isEqualToString:#" "])) {
doubleSpace=NO;}
}
else {
if ([currentLetter isEqualToString:#" "]) {
doubleSpace=NO;
}
}
if ((unwantedCharacters.location!=NSNotFound)&&(doubleSpace))
{
cleanStringOutput=[NSString stringWithFormat:#"%#%#", cleanStringOutput, currentLetter];
}
}
if (cleanStringOutput.length>0){
if ([[NSString stringWithFormat:#"%c",[cleanStringOutput characterAtIndex:0]] isEqualToString:#" "]){
cleanStringOutput=[cleanStringOutput substringFromIndex:1];
}
}
[currentLetter release];
[wantedCharacters release];
[cleanStringOutput autorelease];
return cleanStringOutput;
}
Please forgive me if I just asked something painfully obvious.
P.S. And another question. Is it necessary to release the NSRange?
Right here
NSCharacterSet* wantedCharacters=[[NSCharacterSet alloc] init];
wantedCharacters=[ NSCharacterSet
characterSetWithCharactersInString:#"qwertyuiopasdfghjklzxcvbnm"];
You discard your original object and replace it with an autoreleased one
Which will crash when you call
[wantedCharacters release];
Do this
NSCharacterSet* wantedCharacters=[ NSCharacterSet
characterSetWithCharactersInString:#"qwertyuiopasdfghjklzxcvbnm"];
and forget the last
[wantedCharacters release];
There are several mistakes in your code that causes you to lose the reference to the allocated objects, and an example will follow, but a few things:
The easiest solution for all of them, is to use autorelease wherever you call alloc (and remove the release for those objects), for example:
NSString* cleanStringOutput=[[[NSString alloc] initWithString:#""] autorelease];
When you create a variable only to assign to it later, there is no need to allocate, for example:
NSCharacterSet* wantedCharacters; // no need for alloc here
wantedCharacters=[ NSCharacterSet characterSetWithCharactersInString:#"qwertyuiopasdfghjklzxcvbnm"];
In general - if you didn't allocate the object, you don't release it.
currentLetter=[NSString stringWithFormat:#"%c",[input characterAtIndex:i]];
Returns an autoreleased string - no need to alloc/init it above.
NSString* currentLetter =[[NSString alloc] initWithString:#" "];
So calling
[currentLetter release];
Will probably cause problems.
You alloc/init a wantedCharacters object, then reassign it using a convenience function. The reassignment creates a zombie with the first object.
The convenience function puts the new object instance into the autorelease pool.
Then you call release. Since it was only retained once, it gets deallocated.
Later, the autorelease pool calls release on it, but it has already been deallocated. This causes the crash.

Memory Management Headache

I get leaks if I dont put it in dealloc. I get a crash EXC_BAD_ACCESS If I do. I cannot see anything wrong with this code. The bad access is pointed at [events release]. Have I made a mistake in the code below or is Instruments just having a laugh at my expense?
events is an NSArray
#interface EventsViewController : UITableViewController
{
#private
NSArray *events;
}
- (void)viewDidLoad
{
events = [[self getEvents] retain];
}
- (void)dealloc
{
[events release];
[super dealloc];
}
- (NSArray*)getEvents
{
NSMutableArray *response = [[[NSMutableArray alloc] init] autorelease];
//Some sql
while(sqlite3_step(statement) == SQLITE_ROW)
{
Event *event = [[[Event alloc] init] autorelease];
event.subject = [NSString stringWithUTF8String:(char *)sqlite3_column_text(statement, 0)];
[response addObject:event];
}
return response;
}
Update
A lot of you are saying the code is fine which is a plus. I dont manipulate events elsewhere - I have removed any code that does to try and single out the crash. Perhaps its in the parent view?
This is the click event that pushes the EventsViewController:
- (void)eventsClick:(id)sender
{
EventsViewController *eventsViewController = [[EventsViewController alloc] initWithNibName:#"EventsViewController" bundle:nil];
eventsViewController.anywhereConnection = anywhereConnection;
eventsViewController.contact = contact;
[[self navigationController] pushViewController:eventsViewController animated:YES];
[eventsViewController release];
}
The crash is actually happening when I return to the parent view. (I think it is considered a parent in this scenario). But perhaps the [eventsViewController release] just triggers dealloc in the EventViewController.
Have you considered just refactoring your code to use ARC? It works with iOS 4 and up and will make your life a lot easier. There are plenty of tutorials out there that will guide you how to do it, and will remove the need to manually figure out the nuances of memory management.
If your Events object has property 'subject' set as assign, then the results of stringWithUTF8String: will not be retained. (Same thing if Events is a C++ object.)
The stringWithUTF8String: method returns an auto-released object that will be released at the next turn of the event loop.
There is a huge difference when you reference a variable via "self", and when you don't.
When you use
events = [[self getEvents] retain];
the memory allocated in getEvents never gets stored in the class property and is basically a leak.
You need to use
self.events = [self getEvents]; // no need to use retain if property is correctly defined.
Then
[events release];
should work fine.
try putting
events = nil;
in dealloc.

NSNumberFormatter leaks on NSCFNumber getObjectValue

I created a common method "isValidAmount" to check if the user inputs a correct amount in UITextField. This is working, but the problem is, I am getting leaks when the number is invalid. The leaked object is "NSCFNumber" and the responsible for that is "getObjectValue". I don't know what else to do. I already release the "formatter" below. I even tried to release "number" below. But still I keep on getting this leak. Please help.
+ (BOOL) isValidAmount:(NSString *)amount {
NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
[formatter setNumberStyle:NSNumberFormatterDecimalStyle];
NSNumber *number = [formatter numberFromString:amount];
[formatter release];
if (!number) {
return NO;
}
return YES;
}
By inspection, there is nothing wrong with that code.
Does it also leak on the device? Can you post the exact backtrace of the allocation that is leaked?

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]];

iPhone Memory Debugging

I'm using Instruments to try to determine if there are places in my application that I could be more efficient with use of memory. I've taken the time to get somewhat familiar with Instruments but I'm generally a newbie with hunting memory management issues having come from a Java background. I seem to be using about 1.82mb by calls to this method:
+ (NSString *)stringFromDateWithFormat:(NSDate *)date withFormat:(NSString *)format
{
NSDateFormatter *dateFormatter;
NSString *result;
if (nil == date || nil == format)
return nil;
result = nil;
if (nil != (dateFormatter = [[NSDateFormatter allocWithZone:[self zone]] init])) {
[dateFormatter setDateFormat:format];
if (nil != (result = [dateFormatter stringFromDate:date])) {
[dateFormatter release];
return result;
}
[dateFormatter release];
}
return nil;
}
As I'm releasing the date formatter I'm wondering if the NSString result is my issue. It seems to me that the stringFromDate library call would return an autoreleased object so there's nothing I can do to 'manually' manage it. A bit unsure of how to optimize this method.
Is this method getting called a lot of times in a loop? Autoreleased objects only get released when the NSAutoreleasePool they're in gets released. As I understand it, the default autorelease pool is created and release every event loop. It's possible you're creating too many autoreleased objects in the course of a single event loop. The solution is to create your own NSAutoreleasePool in an appropriate place, and release it to clear up autoreleased objects. An extreme example that illustrates the point:
int i;
NSAutoreasePool* pool = nil;
for (i = 0; i < 1000000; ++i) {
/* Create a new pool every 10000 iterations */
if ((i % 10000) == 0) {
if (pool) [pool release];
pool = [[NSAutoreleasePool alloc] init];
}
[someObj someMethodThatCreatesAutoreleasedObjects];
}
[pool release];
In that example, the current pool is released every 10,000 iterations and a new one is created. You can read more about memory management in the Memory Management Programming Guide section on autorelease pools.
You need to return an autoreleased object anyway, so there's really nothing you should be doing about the result string. I don't see any mistakes related to memory, but your code is definitely more verbose than needed. Keep in mind that in Objective-C, if you call a method on nil, you get back nil (or 0 for an integer, but not for floating point values). You can take out all those if statements and the two return paths, and your code will still work the same way. Also, I would just use alloc instead of allocWithZone.
I am not a 100% with this. I am also just learning Mac/Iphone development. But you can use the auto release pool to help with memory management. It is used to get around release problems.
Here is an article with lots on memory management. Check out the left sided menu.