Surprising IPhone leak - iphone

So I'm running instruments on my app, and getting a leak that I could have sworn I was doing right.
+ (NSMutableArray *)decode:(NSDictionary *)encoded_faculty_array
{
NSArray *faculty_id_data = [encoded_faculty_array objectForKey:#"faculty_id"];
NSArray *faculty_first_name = [encoded_faculty_array objectForKey:#"first_name"];
NSArray *faculty_last_name = [encoded_faculty_array objectForKey:#"last_name"];
NSMutableArray* faculty_array = [[NSMutableArray alloc] init];
for(int a = 0; a < [faculty_id_data count]; a++)
{
Faculty *new_fac = [[Faculty alloc] initWithFacultyId:[Dearray clean:[faculty_id_data objectAtIndex:a] withDefault:#"0"]
andFirstName:[Dearray clean:[faculty_first_name objectAtIndex:a] withDefault:#"Name not found"]
andLastName:[Dearray clean:[faculty_last_name objectAtIndex:a] withDefault:#" "]
andBio:nil
andDegrees:nil
andTitle:nil];
[faculty_array addObject:new_fac];
[new_fac release];
}
[faculty_array autorelease];
return faculty_array;
}
It's reporting a leak on new_fac. I released it immediately after I called it though. Any idea what could be causing that problem?
Thanks.
EDIT
Here is code for intializing the Faculty instance new_fac:
- (id) initWithFacultyId:(NSString *)new_id andFirstName:(NSString *)new_first_name andLastName:(NSString *)new_last_name andBio:(NSString *)new_bio andDegrees:(NSString *)new_degrees andTitle:(NSString *)new_title
{
if (self = [super init]) {
self.faculty_id = new_id;
self.first_name = new_first_name;
self.last_name = new_last_name;
self.bio = new_bio;
self.degrees = new_degrees;
self.title = new_title;
}
return self;
}

You could try checking to see if the properties of Faculty and make sure those NSStrings(firstName, lastName etc) are being released properly.
If those strings are properties that are 'retained' they should be released in Faculty dealloc.

Related

Wierd behaviour of a singleton object

I'm having really weird situation. I create a singletone object of a class named "Profile like this:
static Profile *currentProfile;
+ (Profile *)currentProfile
{
#synchronized(self)
{
if (currentProfile == nil)
currentProfile = [[Profile alloc] init];
}
return currentProfile;
}
- (id)init
{
self = [super init];
if (self)
{
// Initialization code here.
isChecked = [[[NSUserDefaults standardUserDefaults] objectForKey:#"isChecked"] boolValue];
if (isChecked)
{
NSLog(#"isChecked block is called");
NSData *data = [[NSUserDefaults standardUserDefaults] objectForKey:#"myEncodedObjectKey"];
self = (Profile *) [NSKeyedUnarchiver unarchiveObjectWithData:data];
[self retain];
for (int i = 0; i < self.avatar.count; i++)
[self.avatar replaceObjectAtIndex:i withObject:[UIImage imageWithData:[self.avatar objectAtIndex:i]]];
}
else
{
password = #"";
pfefferID = #"";
email = #"";
avatar = [[NSMutableArray alloc] initWithObjects:
[UIImage imageNamed:#"empty_image.png"],
[UIImage imageNamed:#"empty_image.png"],
[UIImage imageNamed:#"empty_image.png"],
[UIImage imageNamed:#"empty_image.png"],
[UIImage imageNamed:#"empty_image.png"],nil];
isBoy = YES;
friends = [[NSMutableDictionary alloc] init];
rating = 0;
}
}
return self;
}
In init method i check a certain condition stored in NSUserDefaults by using BOOL variable named "isChecked". isChecked is equal to YES and everything works fine. But... i create this Profile object in AppDelegate file like this
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
users = [[NSMutableDictionary alloc] init];
usersForLeaderboardFromServer = [[NSMutableDictionary alloc] init];
listOfFriendsFromServer = [[NSMutableDictionary alloc] init];
currentProfile = [Profile currentProfile];
sessionID = 0;
if (!currentProfile.isChecked)//why????
NSLog(#"not checked");
if (currentProfile.isChecked)
{
[self getUsersForLeaderboardFromServer];
MainMenuView *mainMenu = [[[MainMenuView alloc] init] autorelease];
[self.navigationController pushViewController:mainMenu animated:YES];
}
}
So the same isChecked variable which a moment (far less than a moment actually) ago was equal to YES gets equal to NO when being used in application didFinishLaunchingWithOptions method by accessing it via dot. What's going on? I'm able to handle it but i'm just curious about this situation. Do you know what's wrong with it?
You're reassigning self in init, so you're returning the new object rather than the one you set isChecked on. See this code:
self = (Profile *) [NSKeyedUnarchiver unarchiveObjectWithData:data];
[self retain];
It's slightly awkward to do things like you've got - I would certainly not recommend replacing it in the way you have. For a start, the value you set to the static currentProfile is not being updated when you reassign self so that's still the old one. And also you're not releasing the old self when you reassign.
To fix it you could do something like this:
id newSelf = (Profile *) [NSKeyedUnarchiver unarchiveObjectWithData:data];
newSelf.isChecked = isChecked;
[self release];
self = [newSelf retain];
But I don't really advocate that personally. I suggest you load in the object from your archive and then proceed to update yourself with it rather than reassigning self.

Adding custom defined objects to NSMutableArray overwrite the whole array

-(id) initWithData:(NSString *)lastName: (NSString *)firstName{
self->firstname = firstName;
self->lastname = lastName;
return self;
}
-(void) printData {
NSLog(#"firstname: %#", firstname);
NSLog(#"lastname: %#", lastname);
}
so whenever I create a new object using the above init function. And Add objects to a NSMutableArray, using the addObject function.
NSMutableArray *objectArray = [[NSMutableArray alloc] init];
CustomObject *tempObject = [[CustomObject alloc] initWithData: #"smith": #"john"];
CustomObject *tempObjectb = [[CustomObject alloc] initWithData: #"brown": #"william"];
[objectArray addObject:tempObject];
[objectArray addObject:tempObjectb];
[[objectArray objectAtIndex:0] printData];
[[objectArray objectAtIndex:1] printData];
objects at index 1, and 0 always equal the whichever object was added to the array last.
This also happens if I use a for loop, or have more than 2 objects, all values when printed, turn to the values of the last added object to the objectArray. Let me know if there is any information that I am missing.
Is there something that I am missing?
Fix your initWithData:lastName: implementation as following:
-(id) initWithData:(NSString *)lastName: (NSString *)firstName
{
self = [super init];
if ( nil != self ) {
self->firstname = [firstName retain];
self->lastname = [lastName retain];
}
return self;
}

execute addObject, but NSMutableArray has no object

I try to use to codes below to add object to NSMutableArray
NSMutableArray* multipartData;
- (void)processDataChunk:(NSData *)postDataChunk
{
if (!postHeaderOK)
{
UInt16 separatorBytes = 0x0A0D;
NSData* separatorData = [NSData dataWithBytes:&separatorBytes length:2];
for (int i = 0; i < [postDataChunk length] - l; i++)
{
NSRange searchRange = {i, l};
if ([[postDataChunk subdataWithRange:searchRange] isEqualToData:separatorData])
{
NSRange newDataRange = {dataStartIndex, i - dataStartIndex};
dataStartIndex = i + l;
i += l - 1;
NSData *newData = [postDataChunk subdataWithRange:newDataRange];
if ([newData length])
{
[multipartData addObject:newData]; //A:set break point here
}
}
}
}
}
I set breakpoint at A:, and found that newData is not nil.
What is wrong with my codes?
Welcome any comment
You declare multipartData but do not allocate or initialize it. Somewhere before adding objects you must have
NSMutableArray *multipartData = [[NSMutableArray alloc] init];
or possibly
NSMutableArray *multipartData = [[[NSMutableArray alloc] init] autorelease];
as your needs dictate. But you must allocate and initialize multipartData before adding to or accessing anything in it.

How to solve Memory leaks for following Sqlite code?

I am getting memory leaks in Instruments in the following Sqlite Code.
NSArray *result = [self executeQuery:sql arguments:argsArray];
It calls following method.
- (NSArray *)executeQuery:(NSString *)sql arguments:(NSArray *)args {
sqlite3_stmt *sqlStmt;
if (![self prepareSql:sql inStatament:(&sqlStmt)])
return nil;
int i = 0;
int queryParamCount = sqlite3_bind_parameter_count(sqlStmt);
while (i++ < queryParamCount)
[self bindObject:[args objectAtIndex:(i - 1)] toColumn:i inStatament:sqlStmt];
NSMutableArray *arrayList = [[NSMutableArray alloc] init];
int columnCount = sqlite3_column_count(sqlStmt);
while ([self hasData:sqlStmt]) {
NSMutableDictionary *dictionary = [[NSMutableDictionary alloc] init];
for (i = 0; i < columnCount; ++i) {
id columnName = [self columnName:sqlStmt columnIndex:i];
id columnData = [self columnData:sqlStmt columnIndex:i];
[dictionary setObject:columnData forKey:columnName];
}
[arrayList addObject:[dictionary autorelease]];
}
sqlite3_finalize(sqlStmt);
return arrayList;
}
How do I solve it ?
We'd need to see the code of your executeQuery method - it should be returning an auto-released result, but perhaps it isn't.
You could try ;
NSArray *result = [[self executeQuery:sql arguments:argsArray] autorelease];
But I'd be wary of just blindly trying that without actually seeing what executeQuery does in detail.
EDIT:
OK, here's your problem;
NSMutableArray *arrayList = [[NSMutableArray alloc] init];
Either create it as an auto-released array, or finish the method with;
return [arrayList autorelease];

build and analyze not working in my project

In my iPhone Project when i select build and analyze (shift + mac + A ) it will give me all potential memory leak in my project... but in my current project it is not working... when i intentionally put a memory leak and select build and analyze... it doesn't give me any potential memory leak as analyzer result
if i write
NSMutableArray *tempArray = [[NSMutableArray alloc] initWithCapacity:6];
NSMutableArray *tempArrayfinal = [[NSMutableArray alloc] initWithCapacity:12];
and doesn't release it... it is not giving me any potential leak but if i write
NSString *leakyString = [[NSString alloc] initWithString:#"Leaky String "];
NSLog(#"%#",leakyString);
here it gives me potential leak as analyzer result...why it is not giving potential leak in NSMutableArray and why it gives potential leak in NSString ?... how can i rely on Build and analyze for memory leak...
I've run the app with Leak tool and it is showing me leak in tempArray and tempArrayfinal
Here is my function
- (void)viewDidLoad
{
[super viewDidLoad];
maxOnSnaxAppDelegate *delegate = (maxOnSnaxAppDelegate *)[[UIApplication sharedApplication] delegate];
lblMessage.tag = MESSAGE_LABEL;
lblGuess.tag = GUESS_LABEL;
lblScore.tag = SCORE_LABEL;
self.gameCompleteView.tag = FINAL_SCORE_VIEW;
lblFinalScore.tag = FINAL_SCORE_LABEL;
lblGuess.text = #"";
lblMessage.text = #"";
lblScore.text = #"";
int row = 0;
int column = 0;
maxImagrArray = [[NSMutableArray alloc] init];
for(UIView *subview in [self.view subviews]) {
if([subview isKindOfClass:[CustomImageView class]])
{
[subview removeFromSuperview];
}
}
for(int i = 0 ; i < 12 ; i++)
{
if(i%3 == 0 && i != 0)
{
row++;
column = -1;
}
if(i != 0 )
{
column++;
//row = 0;
}
CustomImageView *tempImageView = [[CustomImageView alloc] initWithImage:[UIImage imageNamed:#"max-img.png"]];
tempImageView.frame = CGRectMake((column*tempImageView.frame.size.width) + 45, (row*tempImageView.frame.size.height)+ 60, tempImageView.frame.size.width, tempImageView.frame.size.height);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextClearRect(context, tempImageView.bounds);
[self.view addSubview:tempImageView];
tempImageView.tag = i+1;
tempImageView.userInteractionEnabled = YES;
[maxImagrArray addObject:tempImageView];
[tempImageView setIndex:i];
[tempImageView release];
}
NSMutableArray *tempArray = [[NSMutableArray alloc] initWithCapacity:6];
NSMutableArray *tempArrayfinal = [[NSMutableArray alloc] initWithCapacity:12];
for(int i = 0 ; i < 12 ; i++)
{
if(i < 6)
{
int temp = (arc4random() % 10) + 1;
NSString *tempStr = [[NSString alloc] initWithFormat:#"%d",temp];
[tempArray insertObject:tempStr atIndex:i];
[tempArrayfinal insertObject:tempStr atIndex:i];
[tempStr release];
}
else
{
int temp = (arc4random() % [tempArray count]);
[tempArrayfinal insertObject: (NSString *)[tempArray objectAtIndex:temp] atIndex:i];
//int index = [(NSString *)[tempArray objectAtIndex:temp] intValue];
[tempArray removeObjectAtIndex:temp];
}
CustomImageView *tmpCustom = [maxImagrArray objectAtIndex:i];
tmpCustom.frontImageIndex = [(NSString *)[tempArrayfinal objectAtIndex:i] intValue];
NSLog(#"%d",tmpCustom.frontImageIndex);
}
[maxImagrArray release];
delegate.time = 60.0;
timer = nil;
timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(countDown) userInfo:nil repeats:YES];
delegate.view = self.view;
//[tempArray release];
//[tempArrayfinal release];//these 2 lines are deliberately commented to see
//...it is not showing any potential memory leak though....
delegate.viewController = self;
}
please help...
[tempArray insertObject:tempStr atIndex:i];
[tempArrayfinal insertObject:tempStr atIndex:i];
are the culprits... when i uncomment these 2 lines.. it stops giving me the warning... i don't know why...
You shouldn't really rely on the Build and Analyze tool. It does not always catch all leaks. Threre is no substitute for following the memory management rules from apple (apart from garbage collection on OS X). However, I'm not sure why it isn't catching such a simple leak. I tried at line in a method and it did give me a result. Are you sure its not in an if statement, because I've found that sometimes in an if statement it won't correct you.