views:

35

answers:

1

I have a UIViewController (called AdjustViewController) that presents another UIViewController (called SourcePickerViewController) with a UIPickerView modally. I generate instances of the AdjustViewController and they in turn make a SourcePickerViewController. I make an NSDictionary and assign it and an integer to the AdjustViewController and it in turn sets the same properties in the SourcePickerController. This way I can reuse the controllers. The NSDictionary get set up in a UITableViewController that has all the AdjustViewControllers in it.

The problem comes when some of the pickers should have 1 component and some should have 2. The integer that I pass along is called numberOfComponents When I make a picker with numberOfComponents = 1 somehow it's changing to = 2 but I can't see how. I have NSLogs all over the place and I can see it happen as soon as the picker delegate method numberOfComponentsInPickerView is called. It's 1 right before and 2 right after.

There's obviously more code, but I think I have all the important parts. Although if that were true, maybe I'd know where the problem is!


Inside MenuViewController.m

- (void)viewDidLoad {
    NSLog(@"ChemicalViewController launched");
    self.title = @"Adjust Chemicals";
    NSMutableArray *array = [[NSMutableArray alloc] init];

// Chlorine Controller
    AdjustViewController *chlorineAdjustViewController = [[AdjustViewController alloc] initWithNibName:@"AdjustViewController" bundle:nil];
    chlorineAdjustViewController.title = @"FC - Free Chlorine";
    chlorineAdjustViewController.numberOfComponents = 2;
    NSLog(@"Generating chlorine source dictionary");
    NSDictionary *chlorineSourceDictionary = [self generateChlorineDictionary];
    chlorineAdjustViewController.dictionaryOfSources = chlorineSourceDictionary;
    [chlorineSourceDictionary release];
    [array addObject:chlorineAdjustViewController];
    [chlorineAdjustViewController release];

// CYA Controller
    AdjustViewController *cyaAdjustViewController = [[AdjustViewController alloc] initWithNibName:@"AdjustViewController" bundle:nil];
    cyaAdjustViewController.title = @"CYA - Cyanuric Acid";
    cyaAdjustViewController.numberOfComponents = 1;
    NSLog(@"Generating cya source dictionary");
    NSDictionary *cyaSourceDictionary = [self generateCYADictionary];
    cyaAdjustViewController.dictionaryOfSources = cyaSourceDictionary;
    [cyaSourceDictionary release];
    [array addObject:cyaAdjustViewController];
    [cyaAdjustViewController release];

Inside AdjustViewController.m

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

#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 {


    sourceField.text = [[NSString alloc] initWithFormat:@"%@, %@", source, concentration];
    [self updateAdvice];
    NSLog(@"Returned source = %@, concentration = %@, sourceConstant = %1.7f, isLiquid = %d", source, concentration, constant, isLiquid);
    [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];
}

Inside SourceViewController.m

- (void)viewDidLoad {
    NSLog(@"SourcePickerViewController launched");
    NSLog(@"viewDidLoad");
    NSLog(@"Received numberOfComponents %d", self.numberOfComponents);
    self.chemicalSources = dictionaryOfSources;
    NSArray *components = [self.chemicalSources allKeys];
    NSArray *sorted = [components sortedArrayUsingSelector:@selector(compare:)];
    self.sources = sorted; // This array has the chemical sources

    if (self.numberOfComponents = 2) {
        NSString *selectedSource = [self.sources objectAtIndex:0];
        NSArray *chemArray = [self.chemicalSources objectForKey:selectedSource];
        NSMutableArray *concentrationArray = [[NSMutableArray alloc] init];
        int num = [chemArray count];
        for (int i=0; i<num; i++) {
            [concentrationArray addObject:[[chemArray objectAtIndex:i] chemConcentration]];
        }
        self.concentrations = concentrationArray;
    }
    [super viewDidLoad];
}

    #pragma mark -
    #pragma mark Picker Data Source Methods

- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView {
    NSLog(@"numberOfComponentsInPickerView, self.numberOfComponents = %d", self.numberOfComponents);
    return self.numberOfComponents;
}

- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component {
    NSLog(@"numberOfRowsInComponent, self.numberOfComponents = %d", self.numberOfComponents);
    if (component == kSourceComponent)
        return [self.sources count];
    return [self.concentrations count];
}

#pragma mark Picker Delegate Methods

- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component {
    if (component == kSourceComponent)
        return [self.sources objectAtIndex:row];
    return [self.concentrations objectAtIndex:row];
}

- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component {
    NSLog(@"didSelectRow, self.numberOfComponents = %d", self.numberOfComponents);
    if (numberOfComponents = 2) {
        if (component == kSourceComponent) {
            NSString *selectedSource = [self.sources objectAtIndex:row];
            NSArray *chemArray = [self.chemicalSources objectForKey:selectedSource];
            NSMutableArray *concentrationArray = [[NSMutableArray alloc] init];
            int num = [chemArray count];
            for (int i=0; i<num; i++) {
                [concentrationArray addObject:[[chemArray objectAtIndex:i] chemConcentration]];
            }
    self.concentrations = concentrationArray;
    [picker selectRow:0 inComponent:kConcentrationComponent animated:YES];
    [picker reloadComponent:kConcentrationComponent];
    }
}
}

- (CGFloat)pickerView:(UIPickerView *)pickerView widthForComponent:(NSInteger)component {
    if (component == kConcentrationComponent)
        return 90;
    return 205;
}
+1  A: 

I didn't look through all of your code; Instead, I'd recommend writing out the properties for numberOfComponents instead of @synthesize'ing them. Just get rid of your @synthesize, and make:

 - (int)numberOfComponents {
   return m_numberOfComponents;
}

and

 - (void)setNumberOfComponents(int aNumberOfComponents) {
   m_numberOfComponents = aNumberOfComponents;
}

Then, set a breakpoint in your setNumberOfComponents function, and you should be able to see whenever it's getting called, so you can see what is going on. I hope that helps!

Perrako
Thanks - I implemented them like this:`- (int)numberOfComponents { return numberOfComponents;}` and `- (void)setNumberOfComponents:(int)aNumberOfComponents { numberOfComponents = aNumberOfComponents;}`And I can see it get called and the caller is sending it a `1` and it seems to get called twice before the picker is presented.First time `-[AdjustViewController getChemicalSource:]` and second time `-[SourcePickerViewContronller viewDidLoad]`.
Steve
If you hover over the expression in getChemicalSource it's this line: `sourcePickerViewController.numberOfComponents = self.numberOfComponents;` with the left side showing `0` and the right side showing `1`.The second time in viewDidLoad, it's this line: `if (self.numberOfComponents = 2) {` and it shows a value of `1` but right after that, my `NSLogs` show that it's `2` again.
Steve
Ah -- your comment had me catch it. (self.numberOfComponents = 2) should be (self.numberOfComponents == 2). Annoying mistake, isn't it?
Perrako
Wow - that was it! So when I had `if (self.numberOfComponents = 0)` did that actually `set` it to `2` rather than evaluate it? Would it be correct to say that a single `=` always mean `set the left side equal to the right side of the `=` and the `==` is for evaluating whether the two sides are equal? Annoying, yes! But satisfying to be past it. Thanks so much!
Steve
Ah, yes, I figured you knew that since you had it right elsewhere in your code! The single = sign is always, always, always assignment. In addition to setting a new value, it also returns that new value. The double == sign is always comparison. It returns a boolean true or false. The reason it sometimes ends up doing what you expect is that in the C family of languages, any value that is not 0 is treated as true, and 0 is treated as false. Since your assignment returns whatever value is set, this can be evaluated. So, if (self.numberOfComponents = 0) will always be false! Hope that helps.
Perrako
It helps a lot! Some of my code (like the picker delegate methods) started as code from a book I've been reading to learn programming. I used to program in Basic on my Apple ][+ back in the day, but just started this a month or so ago, so all this C stuff is new. Without Stack Overflow and NSLog I'd give up!
Steve
Keep going! If you're still mostly using NSLog debugging, though, as nice as it is, try making the step up to using the XCode debugger. It's not hard to use, and the little time investment to learn it will pay off immensely.
Perrako