Мой подкласс как свойство не будет принимать новые значения для его свойств - PullRequest
0 голосов
/ 27 июля 2010

I have a UIViewController, который представляет другой UIViewController с помощью сборщика и возвращает четыре значения.У меня также есть специальный класс с именем Chemical, который может содержать эти значения.В методе делегата, который получает значения (didSelectSource в AdjustViewController), я ставлю точку останова и вижу, что возвращаются правильные значения, но когда я пытаюсь присвоить их моему локальному Chemical, называемому selectedChemical значения не прилипают, и я получаю EXC_BAD_ACCESS.Когда я нахожу курсор над selectedChemical.chemName, он говорит: «вне области видимости».

Я не понимаю.


#import <Foundation/Foundation.h>

@interface Chemical : NSObject {

    NSString *chemName;
    NSString *chemConcentration;
    float chemConstant;
    BOOL chemIsLiquid;  
}

@property (nonatomic, retain) NSString *chemName;
@property (nonatomic, retain) NSString *chemConcentration;
@property float chemConstant;
@property BOOL chemIsLiquid;    

- (id)initWithChemical:(NSString *)chemical 
      andConcentration:(NSString *)concentration 
           andConstant:(float)constant 
           andIsLiquid:(BOOL)isLiquid;
@end

#import "Chemical.h"


@implementation Chemical

@synthesize chemName;
@synthesize chemConcentration;
@synthesize chemConstant;
@synthesize chemIsLiquid;   

- (id)initWithChemical:(NSString *)chemical 
      andConcentration:(NSString *)concentration 
           andConstant:(float)constant 
           andIsLiquid:(BOOL)isLiquid {

    if((self = [super init])) {
        self.chemName = chemical;
        self.chemConcentration = concentration;
        self.chemConstant = constant;
        self.chemIsLiquid = isLiquid;
    }
    return self;
}

@end

#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)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);
        }
        delta = [targetLabel.text intValue] - [startingLabel.text intValue]; // The difference between target and starting levels
        NSLog(@"  delta = %d", delta);
        selectedChemSourceAmount = delta * [volumeField.text intValue] * selectedChemConstant; // Calculates the amount of source chemical necessary in ounces
        NSLog(@"  selectedChemSourceAmount = %1.1f", selectedChemSourceAmount);

// If delta is positive, add chemical
        if (delta > 0) {
            NSLog(@">> Delta > 0");
            if (selectedChemIsLiquid) {
                if (selectedChemSourceAmount > 128) { // Amount is more than a gallon
                    selectedChemSourceAmount = selectedChemSourceAmount / 128;
                    messageBody = [[NSString alloc] initWithFormat:@"To increase %@ by %d ppm, add %1.1f gal of ", self.title, delta, selectedChemSourceAmount]; 
                }
                else { // Less than a gallon
                    messageBody = [[NSString alloc] initWithFormat:@"To increase %@ by %d ppm, add %1.1f fl oz of ", self.title, delta, selectedChemSourceAmount];
                }
            }
            else { // Chemical is a solid
                if (selectedChemSourceAmount > 16) { // Amount is more than a pound
                    selectedChemSourceAmount = selectedChemSourceAmount / 16;
                    messageBody = [[NSString alloc] initWithFormat:@"To increase %@ by %d ppm, add %1.1f lb of ", self.title, delta, selectedChemSourceAmount]; 
                }
                else { // Less than a pound
                    messageBody = [[NSString alloc] initWithFormat:@"To increase %@ by %d ppm, add %1.1f oz of ", self.title, delta, selectedChemSourceAmount];
                }
            }
            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

Ответы [ 2 ]

2 голосов
/ 27 июля 2010

Вы не звоните [super init].

Ваш init метод должен выглядеть примерно так:

- (id)initWithChemical:(NSString *)chemical 
      andConcentration:(NSString *)concentration 
           andConstant:(float)constant 
           andIsLiquid:(BOOL)isLiquid {

    if((self = [super init])) {
        self.chemName = chemical;
        self.chemConcentration = concentration;
        self.chemConstant = constant;
        self.chemIsLiquid = isLiquid;
    }
    return self;
}

Кроме того, я не вижу, где вы создаете экземплярваша Chemical переменная экземпляра.Убедитесь, что он создан перед назначением свойств.

1 голос
/ 28 июля 2010

У вас есть несколько проблем, которые не могут решить эту проблему

  1. Как уже упоминалось, ваш инициатор должен позвонить [super init]
  2. Классы, которые сохранили свойства, нуждаются в сообщении dealloc, которое устанавливает их в ноль

И некоторые вещи, которые могут помочь

  1. Что такое messageBody? Вы освобождаете его, но оно выделяется только в том случае, если delta> 0. Вы должны освобождать, только если вы выделяете Используйте это, и вам не нужно выпускать

    messageBody = [NSString stringWithFormat:@"To increase %@ by %dppm, add %1.1f gal of ", self.title, delta, sourceAmount]; 
    
  2. То же самое для составного имени - иногда вы выделяете, а иногда назначаете из свойства. Вы должны освобождать, только если вы распределяете или сохраняете (или вызываете метод, который делает это для вас). Используйте stringWithFormat в другом, и не выпускайте

  3. То же самое с adviceMessage - иногда вы выделяете, а иногда нет, но вы всегда отпускаете.

Пожалуйста, прочтите это, чтобы узнать правила памяти для iPhone:

http://loufranco.com/blog/files/managing-memory-iphone.html

Я также написал это, чтобы помочь людям отлаживать EXC_BAD_ACCESS

http://loufranco.com/blog/files/Understanding-EXC_BAD_ACCESS.html

...