2010-07-28 24 views
0

我有一種方法,當在其中放置一個斷點並將鼠標懸停在一個字符串上時,表示它是out of scope,您可以深入查看NSString對象,看起來像是永遠。我試圖把一個屏幕截圖...希望它出現。我覺得我有一些嚴重的內存管理的問題...NSString的超類永遠繼續

http://web.me.com/gazelips/Site/Blank_files/screenshot.jpg

這裏是整個的.h和.m文件。該問題發生在updateAdvice方法中。

#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 
+0

重複出現的超類只是一個調試工具。如同超出範圍的信息一樣。 – Akusete 2010-07-28 05:38:20

+0

您正在查看'isa'指針的列表,而不是超類。 – dreamlax 2010-07-28 06:20:18

回答

2

你看到的沒有超無限鏈(如果你看一下實際的地址,你會看到它的第二次以後不發生變化),你」實際上看着NSObjectmetaclass。請快速閱讀由Matt Gallagher —精彩提供的鏈接—,它將解釋您在調試器中看到的內容。 NSObject元類的元類本身。

1

這實際上很常見,並不一定與代碼中的錯誤有關。

如果在調試器窗口中右鍵單擊字符串對象並選擇「print description to console」,它應該可以正常工作。

0

反正我只是在看你的代碼。什麼是另外兩個人說抱......然而,內存管理問題:

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

我認爲這將是更好地爲您簡單的寫

self.messageBody = [NSString stringWithFormat:@"To increase %@...", self.title]; 

此自動調用您合成存取方法使用@synthesize messageBody。 它會自動釋放舊的字符串,並保留新的字符串。 你現在正在做的是分配一個新的字符串而不釋放舊的字符串。當你已經合成訪問器方法時爲什麼要這樣做呢?

最後,不要忘記在dealloc中正確釋放messageBody,在那裏你應該釋放它。

- (void)dealloc 
{ 
    [messageBody release]; 
    [everythingElseIHaveToRelease release]; 

    [super dealloc]; 
} 

希望有所幫助! H