views:

109

answers:

1

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
+1  A: 

Check this: http://stackoverflow.com/questions/1096352/strange-descriptions-for-arrays-in-xcode-debugger

If this is the case, other objects like NSStrings will be unavailable as well

cesarnicola
I did set the breakpoint at the very end of the method. I'll try putting some earlier and see what's happening. I do know that the strings are not getting the values they should (zeros instead of real numbers) but maybe that's my logic. I had a `=` vs `==` problem before that bit me - a consequence of being new to objective-c.
Steve
I think I see why it's not working now. I used to use a variable called `sourceConstant` but in the process of trying to get the stuff out of my delegate method, I made a set of variables that all start with `selecetedChem`, like `selectedChemConstant`, which is what I should be using. I don't think `sourceConstant` gets set to anything anymore. You wouldn't be able to see that from my code snippet! I'll fix that tonight...
Steve
Great! Tell me if you can fix it! :)
cesarnicola
It works ok now, except that when I set both of my sliders to the same number (as long at they're different, it's ok) the program crashes for `EXC_BAD_ACCESS` The variabls `selectedChemName` and `selectedChemConcentration` both still say `out of scope` when I break point in the `updateAdvice` method - even near the top. Frustrating. I think my memory management is messed up...
Steve
Check out this to debug memory management exceptions :) http://www.codza.com/how-to-debug-exc_bad_access-on-iphone
cesarnicola