Instruments says I have a memory leak, but I don't see it - iphone

I have a method to generate a Deck object (NSObject subclass with an NSMutableArray property) and it populates the array with Card objects (UIView subclass with some integer and one NSString property). When I ask for a Deck I check to see if one already exists (I think) and if so, release it before getting a new one.
The code from my viewcontroller...
#import "FlashTestViewController.h"
#implementation FlashTestViewController
- (IBAction)generateDeck {
if (aDeck != nil) {
[aDeck release];
}
aDeck = [[Deck alloc] initDeckWithOperator:#"+"];
}
- (IBAction)generateCard {
if (aCard != nil) {
[aCard fadeAway];
}
aCard = [aDeck newCardFromDeck];
[self.view addSubview:aCard];
}
- (void)fadeAway {
[aCard removeFromSuperview];
[aCard release];
}
#end
The Deck class is as follows...
#import <Foundation/Foundation.h>
#import "Card.h"
#class Deck;
#interface Deck : NSObject {
NSMutableArray* cards;
}
#property(nonatomic, retain) NSMutableArray* cards;
- (id)initDeckWithOperator: (NSString*)mathOper;
- (id)newCardFromDeck;
#end
- (id)initDeckWithOperator: (NSString*)mathOper {
if (cards != nil) {
[cards release];
}
cards = [[NSMutableArray alloc] init];
for (int i=0; i<11; i++) {
for (int j=0; j<11; j++) {
int xPos = (random() % 220) + 10;
int yPos = (random() % 360) + 10;
Card* aCard = [[Card alloc] initWithFrame:CGRectMake(xPos, yPos, 60, 80)];
aCard.upperOperand = i;
aCard.lowerOperand = j;
aCard.theOperator = mathOper;
aCard.theResult = i + j;
UITextView* upperTextView = [[UITextView alloc] initWithFrame:CGRectMake(5, 5, 50, 20)];
NSString* upperOper = [[NSString alloc] initWithFormat:#" %d", i];
upperTextView.text = upperOper;
[aCard addSubview:upperTextView];
[upperTextView release];
[upperOper release];
UITextView* middleTextView = [[UITextView alloc] initWithFrame:CGRectMake(5, 30, 50, 20)];
NSString* middleOper = [[NSString alloc] initWithFormat:#"%# %d", mathOper, j];
middleTextView.text = middleOper;
[aCard addSubview:middleTextView];
[middleTextView release];
[middleOper release];
UITextView* lowerTextView = [[UITextView alloc] initWithFrame:CGRectMake(5, 55, 50, 20)];
NSString* lowerOper = [[NSString alloc] initWithFormat:#" %d", j+i];
lowerTextView.text = lowerOper;
[aCard addSubview:lowerTextView];
[lowerTextView release];
[lowerOper release];
[cards addObject: aCard];
[aCard release];
}
}
return self;
}
- (id)newCardFromDeck {
int index = random() % [cards count];
Card* selectedCard = [[cards objectAtIndex:index] retain];
[cards removeObjectAtIndex:index];
return selectedCard;
}
#end
I do the same thing when I ask for a new card from the newCardFromDeck method and it works. Any suggestions?
Thanks!

Add this code to your Deck.m file:
- (void)dealloc
{
[cards release];
[super dealloc];
}

Looking at this line of code:
cards = [[NSMutableArray alloc] init];
Do you release cards in your dealloc method? It looks like this could potentially be a memory leak.

aDeck in generateDeck is also be a leak if you don't release it in the view's dealloc.

In newCardFromDeck:
Card* selectedCard = [[cards objectAtIndex:index] retain];
looks like you retain the card and return it somewhere. Where does this return value end up? If it ends up in another variable with a 'retain' property on it, it can get retained a second time (upon assignment to the variable).

Related

how to display images without repeatition from array in objective-c?

I am able to display 5 images out of 8 from an array. But am getting repeated images with this code:
int index1 = arc4random()%8;
UIImage *card1=[UIImage imageNamed:[imageArray objectAtIndex:index1]];
[b1 setImage:card1 forState:UIControlStateNormal];
int index2 = arc4random()%8;
UIImage *card2=[UIImage imageNamed:[imageArray objectAtIndex:index2]];
[b2 setImage:card2 forState:UIControlStateNormal];
int index3 = arc4random()%8;
UIImage *card3=[UIImage imageNamed:[imageArray objectAtIndex:index3]];
[b3 setImage:card3 forState:UIControlStateNormal];
int index4 = arc4random()%8;
UIImage *card4=[UIImage imageNamed:[imageArray objectAtIndex:index4]];
[b4 setImage:card4 forState:UIControlStateNormal];
int index5 = arc4random()%8;
UIImage *card5=[UIImage imageNamed:[imageArray objectAtIndex:index5]];
[b5 setImage:card5 forState:UIControlStateNormal];
Create an NSMutableArray with your original array then shuffle it.
For shuffling you can use this code:
// NSMutableArray_Shuffling.h
#if TARGET_OS_IPHONE
#import <UIKit/UIKit.h>
#else
#include <Cocoa/Cocoa.h>
#endif
// This category enhances NSMutableArray by providing
// methods to randomly shuffle the elements.
#interface NSMutableArray (Shuffling)
- (void)shuffle;
#end
// NSMutableArray_Shuffling.m
#import "NSMutableArray_Shuffling.h"
#implementation NSMutableArray (Shuffling)
- (void)shuffle
{
static BOOL seeded = NO;
if(!seeded)
{
seeded = YES;
srandom(time(NULL));
}
NSUInteger count = [self count];
for (NSUInteger i = 0; i < count; ++i) {
// Select a random element between i and end of array to swap with.
int nElements = count - i;
int n = (random() % nElements) + i;
[self exchangeObjectAtIndex:i withObjectAtIndex:n];
}
}
#end
You can use shuffling like that:
NSMutableArray* array = [NSMutableArray arrayWithArray:imageArray];
[array shuffle];
[array objectAtIndex:0];
[array objectAtIndex:1];
[array objectAtIndex:2];
[array objectAtIndex:3];
[array objectAtIndex:4];
...
Shuffling code came from this question

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

NSString's superclasses go on forever

I've got a method that when put a breakpoint in it and hover over a string, says it's out of scope and you can drill down into the NSString object for what seems like forever. I've tried to put a screen shot... hope it shows up. I think I have some serious memory management problems...
http://web.me.com/gazelips/Site/Blank_files/screenshot.jpg
Here's the whole .h and .m files. The problem occurs in the updateAdvice method.
#import <UIKit/UIKit.h>
#import "SourcePickerViewController.h"
#import "Chemical.h"
#interface AdjustViewController : UIViewController <SourcePickerViewControllerDelegate>{
// IB controls
UITextField *sourceField;
UITextField *volumeField;
UILabel *startingLabel;
UILabel *targetLabel;
UITextView *adviceLabel;
// Setup variables for the kind of chemical
int numberOfComponents;
NSDictionary *dictionaryOfSources;
// Local ivars
float percentRemove;
float gallonsRemove;
float selectedChemSourceAmount;
int delta;
NSString *selectedChemName;
NSString *selectedChemConcentration;
float selectedChemConstant;
BOOL selectedChemIsLiquid;
NSString *compositeName;
NSString *messageBody;
NSString *adviceMessage;
}
#property (nonatomic, retain) IBOutlet UITextField *sourceField;
#property (nonatomic, retain) IBOutlet UITextField *volumeField;
#property (nonatomic, retain) IBOutlet UILabel *startingLabel;
#property (nonatomic, retain) IBOutlet UILabel *targetLabel;
#property (nonatomic, retain) IBOutlet UITextView *adviceLabel;
#property (nonatomic, retain) NSString *selectedChemName;
#property (nonatomic, retain) NSString *selectedChemConcentration;
#property float selectedChemConstant;
#property BOOL selectedChemIsLiquid;
#property (nonatomic, retain) NSString *compositeName;
#property (nonatomic, retain) NSString *messageBody;
#property (nonatomic, retain) NSString *adviceMessage;
#property int numberOfComponents;
#property (nonatomic, retain) NSDictionary *dictionaryOfSources;
- (IBAction)backgroundTap:(id)sender;
//- (IBAction)textFieldDoneEditing:(id)sender;
- (IBAction)startingSliderChanged:(id)sender;
- (IBAction)startingSliderFinishedChanging;
- (IBAction)targetSliderChanged:(id)sender;
- (IBAction)targetSliderFinishedChanging;
- (IBAction)getChemicalSource;
- (void)updateAdvice;
#end
#import "AdjustViewController.h"
#implementation AdjustViewController
#synthesize sourceField;
#synthesize volumeField;
#synthesize startingLabel;
#synthesize targetLabel;
#synthesize adviceLabel;
#synthesize numberOfComponents;
#synthesize dictionaryOfSources;
#synthesize compositeName;
#synthesize messageBody;
#synthesize adviceMessage;
#synthesize selectedChemName;
#synthesize selectedChemConcentration;
#synthesize selectedChemConstant;
#synthesize selectedChemIsLiquid;
- (IBAction)backgroundTap:(id)sender {
[sourceField resignFirstResponder];
[volumeField resignFirstResponder];
[self updateAdvice];
}
- (IBAction)startingSliderChanged:(id)sender {
UISlider *slider = (UISlider *)sender;
int progressAsInt = (int)(slider.value + 0.5f);
NSString *newValue = [[NSString alloc] initWithFormat:#"%d", progressAsInt];
startingLabel.text = newValue;
[newValue release];
}
- (IBAction)targetSliderChanged:(id)sender {
UISlider *slider = (UISlider *)sender;
int progressAsInt = (int)(slider.value + 0.5f);
NSString *newValue = [[NSString alloc] initWithFormat:#"%d", progressAsInt];
targetLabel.text = newValue;
[newValue release];
}
- (IBAction)startingSliderFinishedChanging {
// [self updateAdvice];
}
- (IBAction)targetSliderFinishedChanging {
// [self updateAdvice];
}
// Present the picker for chlorine selection
- (IBAction)getChemicalSource {
SourcePickerViewController *sourcePickerViewController = [[SourcePickerViewController alloc] init];
sourcePickerViewController.delegate = self;
NSLog(#"getChemicalSource setting numberOfComponents %d", self.numberOfComponents);
sourcePickerViewController.numberOfComponents = self.numberOfComponents;
NSLog(#"getChemicalSource sending numberOfComponents %d", sourcePickerViewController.numberOfComponents);
sourcePickerViewController.dictionaryOfSources = self.dictionaryOfSources;
[self presentModalViewController:sourcePickerViewController animated:YES];
[sourcePickerViewController release];
}
- (void)updateAdvice {
NSLog(#"--updateAdvice");
NSLog(#" selectedChemical name = %#", selectedChemName);
NSLog(#" selectedChemical concentration = %#", selectedChemConcentration);
NSLog(#" selectedChemical constant = %1.6f", selectedChemConstant);
NSLog(#" selectedChemical is liquid = %d", selectedChemIsLiquid);
// First check to see if there is a source AND volume, otherwise prompt user to enter them
if ([volumeField.text isEqualToString:#""] || [sourceField.text isEqualToString:#""]) {
adviceMessage = #"Enter a source and volume.";
}
// If there IS a source and volume, calculate!
else {
if ([selectedChemConcentration isEqualToString:#""]) { // If there's no concentration, make a string with just the name
compositeName = selectedChemName;
NSLog(#" compositeName without concentration = %#", compositeName);
}
else { // But if there is a concentration, make a string with the name and concentration and a space between.
compositeName = [[NSString alloc] initWithFormat:#"%# %#", selectedChemName, selectedChemConcentration];
NSLog(#" compositeName with concentration = %# %#", compositeName, selectedChemConcentration);
}
delta = [targetLabel.text intValue] - [startingLabel.text intValue]; // The difference between target and starting levels
NSLog(#" delta = %d", delta);
sourceAmount = delta * [volumeField.text intValue] * sourceConstant; // Calculates the amount of source chemical necessary in ounces
NSLog(#" sourceAmount = %1.1f", sourceAmount);
// If delta is positive, add chemical
if (delta > 0) {
NSLog(#">> Delta > 0");
if (selectedChemIsLiquid) {
if (sourceAmount > 128) { // Amount is more than a gallon
sourceAmount = sourceAmount / 128;
messageBody = [[NSString alloc] initWithFormat:#"To increase %# by %d ppm, add %1.1f gal of ", self.title, delta, sourceAmount];
}
else { // Less than a gallon
messageBody = [[NSString alloc] initWithFormat:#"To increase %# by %d ppm, add %1.1f fl oz of ", self.title, delta, sourceAmount];
}
}
else { // Chemical is a solid
if (sourceAmount > 16) { // Amount is more than a pound
sourceAmount = sourceAmount / 16;
messageBody = [[NSString alloc] initWithFormat:#"To increase %# by %d ppm, add %1.1f lb of ", self.title, delta, sourceAmount];
}
else { // Less than a pound
messageBody = [[NSString alloc] initWithFormat:#"To increase %# by %d ppm, add %1.1f oz of ", self.title, delta, sourceAmount];
}
}
adviceMessage = [[NSString alloc] initWithFormat:#"%#%#.", messageBody, compositeName];
}
// If delta is zero, stay the course
if (delta == 0) {
NSLog(#"== Delta = 0");
adviceMessage = #"You're on target. No action necessary.";
}
// If delta is negative, remove water
if (delta < 0) {
NSLog(#"<< Delta < 0");
adviceMessage = #"You're over target. Remove some water.";
}
}
adviceLabel.text = adviceMessage; // Set the advice label
[messageBody release]; // And get rid of message
[compositeName release];
[adviceMessage release];
}
- (void)viewDidLoad {
NSLog(#"AdjustViewController launched");
sourceField.text = #"";
adviceLabel.text = #"";
percentRemove = 0;
gallonsRemove = 0;
delta = 0;
selectedChemSourceAmount = 0;
// [self updateAdvice];
[super viewDidLoad];
}
- (void)didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
- (void)viewDidUnload {
sourceField = nil;
volumeField = nil;
startingLabel = nil;
targetLabel = nil;
adviceLabel = nil;
dictionaryOfSources = nil;
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)dealloc {
[sourceField release];
[volumeField release];
[startingLabel release];
[targetLabel release];
[adviceLabel release];
[dictionaryOfSources release];
[super dealloc];
}
#pragma mark -
#pragma mark Picker View Delegate Methods
// Returns the values from the picker if a source was chosen
- (void)sourcePickerViewController:(SourcePickerViewController *)controller
didSelectSource:(NSString *)source
andConcentration:(NSString *)concentration
andConstant:(float)constant
andIsLiquid:(BOOL)isLiquid {
selectedChemName = source;
selectedChemConcentration = concentration;
selectedChemConstant = constant;
selectedChemIsLiquid = isLiquid;
// Update the source textfield. If concentration is empty, just use the source otherwise concatenate them
if ([selectedChemConcentration isEqualToString:#""]) {
sourceField.text = [[NSString alloc] initWithFormat:#"%#", selectedChemName];
}
else {
sourceField.text = [[NSString alloc] initWithFormat:#"%# %#", selectedChemName, selectedChemConcentration];
}
// [self updateAdvice];
NSLog(#"Returned source = %#, concentration = %#, constant = %1.7f, isLiquid = %d", source, concentration, constant, isLiquid);
NSLog(#"selectedChemical.chemName = %#, chemConcentration = %#, chemConstant = %1.7f, chemIsLiquid = %d", selectedChemName, selectedChemConcentration, selectedChemConstant, selectedChemIsLiquid);
[self dismissModalViewControllerAnimated:YES];
}
// Returns from the picker without choosing a new source
- (void)sourcePickerViewController:(SourcePickerViewController *)controller
didSelectCancel:(BOOL)didCancel {
// [self updateAdvice];
NSLog(#"Returned without selecting source");
[self dismissModalViewControllerAnimated:YES];
}
#end
What you're seeing there is not an infinite chain of superclasses (if you look at the actual address you'll see it does not change after the second time), you're actually looking at the NSObject metaclass. Have a quick read through that link—wonderfully provided by Matt Gallagher—and it will explain what you're seeing in the debugger. NSObject's metaclass's metaclass is itself.
This is actually quite common and not necessarily anything to do with a bug in your code.
If you right click on the string object in the debugger window and select "print description to console", it should work just fine.
I'm just looking at your code anyway. What the other two people said hold... however, memory management issues:
if (sourceAmount > 16) { // Amount is more than a pound
sourceAmount = sourceAmount / 16;
messageBody = [[NSString alloc] initWithFormat:#"To increase %# by %d ppm, add %1.1f lb of ", self.title, delta, sourceAmount];
}
else { // Less than a pound
messageBody = [[NSString alloc] initWithFormat:#"To increase %# by %d ppm, add %1.1f oz of ", self.title, delta, sourceAmount];
}
[...]
[messageBody release]; // And get rid of message
[compositeName release];
[adviceMessage release];
I think it would be better for you to simply write
self.messageBody = [NSString stringWithFormat:#"To increase %#...", self.title];
This automatically invokes the accessor methods which you synthesized using #synthesize messageBody.
It will automatically release the old string, and retain the new one.
What you are doing right now is allocating a new string without releasing the old string. And why do that yourself when you have already synthesized the accessor methods?
Finally, don't forget to properly release the messageBody in dealloc, where you should be releasing it.
- (void)dealloc
{
[messageBody release];
[everythingElseIHaveToRelease release];
[super dealloc];
}
Hope that helps!
H

Why are my properties `out of scope`?

I have a method to generate some strings based on the values of some variables I get from I picker controller that is presented modally. I get the values back in the delegate method fine and I can assign them to some properties in my view controller successfully. When I call my method to do the updating, I send the values to the console via NSLog and they show up fine there too. But if I put a breakpoint at the end of my method and look at their values just below the NSLogs, the hover-message says out of scope.
EDIT: I went ahead and added the rest of the head and implementation. Maybe someone can see
#import <UIKit/UIKit.h>
#import "SourcePickerViewController.h"
#import "Chemical.h"
#interface AdjustViewController : UIViewController <SourcePickerViewControllerDelegate>{
// IB controls
UITextField *sourceField;
UITextField *volumeField;
UILabel *startingLabel;
UILabel *targetLabel;
UITextView *adviceLabel;
// Setup variables for the kind of chemical
int numberOfComponents;
NSDictionary *dictionaryOfSources;
// Local ivars
float percentRemove;
float gallonsRemove;
float selectedChemSourceAmount;
int delta;
NSString *selectedChemName;
NSString *selectedChemConcentration;
float selectedChemConstant;
BOOL selectedChemIsLiquid;
NSString *compositeName;
NSString *messageBody;
NSString *adviceMessage;
}
#property (nonatomic, retain) IBOutlet UITextField *sourceField;
#property (nonatomic, retain) IBOutlet UITextField *volumeField;
#property (nonatomic, retain) IBOutlet UILabel *startingLabel;
#property (nonatomic, retain) IBOutlet UILabel *targetLabel;
#property (nonatomic, retain) IBOutlet UITextView *adviceLabel;
#property (nonatomic, retain) NSString *selectedChemName;
#property (nonatomic, retain) NSString *selectedChemConcentration;
#property float selectedChemConstant;
#property BOOL selectedChemIsLiquid;
#property (nonatomic, retain) NSString *compositeName;
#property (nonatomic, retain) NSString *messageBody;
#property (nonatomic, retain) NSString *adviceMessage;
#property int numberOfComponents;
#property (nonatomic, retain) NSDictionary *dictionaryOfSources;
- (IBAction)backgroundTap:(id)sender;
//- (IBAction)textFieldDoneEditing:(id)sender;
- (IBAction)startingSliderChanged:(id)sender;
- (IBAction)startingSliderFinishedChanging;
- (IBAction)targetSliderChanged:(id)sender;
- (IBAction)targetSliderFinishedChanging;
- (IBAction)getChemicalSource;
- (void)updateAdvice;
#end
#import "AdjustViewController.h"
#implementation AdjustViewController
#synthesize sourceField;
#synthesize volumeField;
#synthesize startingLabel;
#synthesize targetLabel;
#synthesize adviceLabel;
#synthesize numberOfComponents;
#synthesize dictionaryOfSources;
#synthesize compositeName;
#synthesize messageBody;
#synthesize adviceMessage;
#synthesize selectedChemName;
#synthesize selectedChemConcentration;
#synthesize selectedChemConstant;
#synthesize selectedChemIsLiquid;
- (IBAction)backgroundTap:(id)sender {
[sourceField resignFirstResponder];
[volumeField resignFirstResponder];
[self updateAdvice];
}
- (IBAction)startingSliderChanged:(id)sender {
UISlider *slider = (UISlider *)sender;
int progressAsInt = (int)(slider.value + 0.5f);
NSString *newValue = [[NSString alloc] initWithFormat:#"%d", progressAsInt];
startingLabel.text = newValue;
[newValue release];
}
- (IBAction)targetSliderChanged:(id)sender {
UISlider *slider = (UISlider *)sender;
int progressAsInt = (int)(slider.value + 0.5f);
NSString *newValue = [[NSString alloc] initWithFormat:#"%d", progressAsInt];
targetLabel.text = newValue;
[newValue release];
}
- (IBAction)startingSliderFinishedChanging {
// [self updateAdvice];
}
- (IBAction)targetSliderFinishedChanging {
// [self updateAdvice];
}
// Present the picker for chlorine selection
- (IBAction)getChemicalSource {
SourcePickerViewController *sourcePickerViewController = [[SourcePickerViewController alloc] init];
sourcePickerViewController.delegate = self;
NSLog(#"getChemicalSource setting numberOfComponents %d", self.numberOfComponents);
sourcePickerViewController.numberOfComponents = self.numberOfComponents;
NSLog(#"getChemicalSource sending numberOfComponents %d", sourcePickerViewController.numberOfComponents);
sourcePickerViewController.dictionaryOfSources = self.dictionaryOfSources;
[self presentModalViewController:sourcePickerViewController animated:YES];
[sourcePickerViewController release];
}
- (void)updateAdvice {
NSLog(#"--updateAdvice");
NSLog(#" selectedChemical name = %#", selectedChemName);
NSLog(#" selectedChemical concentration = %#", selectedChemConcentration);
NSLog(#" selectedChemical constant = %1.6f", selectedChemConstant);
NSLog(#" selectedChemical is liquid = %d", selectedChemIsLiquid);
// First check to see if there is a source AND volume, otherwise prompt user to enter them
if ([volumeField.text isEqualToString:#""] || [sourceField.text isEqualToString:#""]) {
adviceMessage = #"Enter a source and volume.";
}
// If there IS a source and volume, calculate!
else {
if ([selectedChemConcentration isEqualToString:#""]) { // If there's no concentration, make a string with just the name
compositeName = selectedChemName;
NSLog(#" compositeName without concentration = %#", compositeName);
}
else { // But if there is a concentration, make a string with the name and concentration and a space between.
compositeName = [[NSString alloc] initWithFormat:#"%# %#", selectedChemName, selectedChemConcentration];
NSLog(#" compositeName with concentration = %# %#", compositeName, selectedChemConcentration);
}
delta = [targetLabel.text intValue] - [startingLabel.text intValue]; // The difference between target and starting levels
NSLog(#" delta = %d", delta);
sourceAmount = delta * [volumeField.text intValue] * sourceConstant; // Calculates the amount of source chemical necessary in ounces
NSLog(#" sourceAmount = %1.1f", sourceAmount);
// If delta is positive, add chemical
if (delta > 0) {
NSLog(#">> Delta > 0");
if (selectedChemIsLiquid) {
if (sourceAmount > 128) { // Amount is more than a gallon
sourceAmount = sourceAmount / 128;
messageBody = [[NSString alloc] initWithFormat:#"To increase %# by %d ppm, add %1.1f gal of ", self.title, delta, sourceAmount];
}
else { // Less than a gallon
messageBody = [[NSString alloc] initWithFormat:#"To increase %# by %d ppm, add %1.1f fl oz of ", self.title, delta, sourceAmount];
}
}
else { // Chemical is a solid
if (sourceAmount > 16) { // Amount is more than a pound
sourceAmount = sourceAmount / 16;
messageBody = [[NSString alloc] initWithFormat:#"To increase %# by %d ppm, add %1.1f lb of ", self.title, delta, sourceAmount];
}
else { // Less than a pound
messageBody = [[NSString alloc] initWithFormat:#"To increase %# by %d ppm, add %1.1f oz of ", self.title, delta, sourceAmount];
}
}
adviceMessage = [[NSString alloc] initWithFormat:#"%#%#.", messageBody, compositeName];
}
// If delta is zero, stay the course
if (delta == 0) {
NSLog(#"== Delta = 0");
adviceMessage = #"You're on target. No action necessary.";
}
// If delta is negative, remove water
if (delta < 0) {
NSLog(#"<< Delta < 0");
adviceMessage = #"You're over target. Remove some water.";
}
}
adviceLabel.text = adviceMessage; // Set the advice label
[messageBody release]; // And get rid of message
[compositeName release];
[adviceMessage release];
}
- (void)viewDidLoad {
NSLog(#"AdjustViewController launched");
sourceField.text = #"";
adviceLabel.text = #"";
percentRemove = 0;
gallonsRemove = 0;
delta = 0;
selectedChemSourceAmount = 0;
// [self updateAdvice];
[super viewDidLoad];
}
- (void)didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
- (void)viewDidUnload {
sourceField = nil;
volumeField = nil;
startingLabel = nil;
targetLabel = nil;
adviceLabel = nil;
dictionaryOfSources = nil;
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)dealloc {
[sourceField release];
[volumeField release];
[startingLabel release];
[targetLabel release];
[adviceLabel release];
[dictionaryOfSources release];
[super dealloc];
}
#pragma mark -
#pragma mark Picker View Delegate Methods
// Returns the values from the picker if a source was chosen
- (void)sourcePickerViewController:(SourcePickerViewController *)controller
didSelectSource:(NSString *)source
andConcentration:(NSString *)concentration
andConstant:(float)constant
andIsLiquid:(BOOL)isLiquid {
selectedChemName = source;
selectedChemConcentration = concentration;
selectedChemConstant = constant;
selectedChemIsLiquid = isLiquid;
// Update the source textfield. If concentration is empty, just use the source otherwise concatenate them
if ([selectedChemConcentration isEqualToString:#""]) {
sourceField.text = [[NSString alloc] initWithFormat:#"%#", selectedChemName];
}
else {
sourceField.text = [[NSString alloc] initWithFormat:#"%# %#", selectedChemName, selectedChemConcentration];
}
// [self updateAdvice];
NSLog(#"Returned source = %#, concentration = %#, constant = %1.7f, isLiquid = %d", source, concentration, constant, isLiquid);
NSLog(#"selectedChemical.chemName = %#, chemConcentration = %#, chemConstant = %1.7f, chemIsLiquid = %d", selectedChemName, selectedChemConcentration, selectedChemConstant, selectedChemIsLiquid);
[self dismissModalViewControllerAnimated:YES];
}
// Returns from the picker without choosing a new source
- (void)sourcePickerViewController:(SourcePickerViewController *)controller
didSelectCancel:(BOOL)didCancel {
// [self updateAdvice];
NSLog(#"Returned without selecting source");
[self dismissModalViewControllerAnimated:YES];
}
#end
Check this: Strange Descriptions for Arrays in XCode debugger
If this is the case, other objects
like NSStrings will be unavailable as
well

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.