iphoneSDK: UINavigationController Back button is causing app to crash
My app is crashing when I move between ViewControllers. This is the sequence that causes the crash salesViewController displays confirmViewController. When I press the back button in confirmViewController to go back to salesViewController, the application crashes.
I am not sure why. Here is the code for both of the controllers.
Thanks in advance.
#import "salesViewController.h"
@implementation salesViewController
@synthesize txtCardNumber;
@synthesize txtExpires;
@synthesize txtGrandTotal;
@synthesize txtZip;
@synthesize txtEmail;
@synthesize txtCCV2;
@synthesize txtInvoice;
//@synthesize button;
@synthesize strSaleType;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
if(self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) {
}
return self;
}
-(IBAction)btnTipCalculator:(id)sender
{
NSLog(@"I was pressed");
tipCalcViewController *tipVC = [[tipCalcViewController alloc] initWithNibName:@"tipCalcView" bundle:nil];
tipVC.delegate = self;
tipVC.passedTotal = txtGrandTotal.text;
[self presentModalViewController:tipVC animated:YES];
[tipVC release];
}
-(IBAction)btnDateSelector:(id)sender
{
NSLog(@"I was pressed");
DatePickerViewController *datePickerViewController = [[DatePickerViewController alloc] initWithNibName:@"datePickerView" bundle:nil];
datePickerViewController.delegate = self;
[self presentModalViewController:datePickerViewController animated:YES];
[datePickerViewController release];
}
-(void)datePickerViewController:(DatePickerViewController *)controller didChooseDate:(NSString *)chosenDate{
NSLog(@"Chosen Date as String: %@", chosenDate );
txtExpires.text = chosenDate;
//do processing here... for example let's set the text of the button to the chosen date
//[button setTitle: chosenDate forState: UIControlStateNormal];
[self dismissModalViewControllerAnimated:YES];
}
//callback for modal tipCalculator
-(void)tipCalcViewController:(tipCalcViewController *)controller didChooseTip:(NSString *)chosenTip
{
NSString *strNewTotal = chosenTip;
//close tip calculator
[self dismissModalViewControllerAnimated:YES];
//update GUI
txtGrandTotal.text = strNewTotal;
}
-(void)btnSubmitClicked
{
NSURL *url = [NSURL URLWithString:@"https://www.eProcessingNetwork.Com/cgi-bin/tdbe/transact.pl"];
//NSURL *url = [NSURL URLWithString:@"https://www.eprocessingnetwork.com/Reflect/Post.pl"];
ASIFormDataRequest *request = [[[ASIFormDataRequest alloc]
initWithURL:url] autorelease];
//get settings
//NSUserDefaults *options = [NSUserDefaults standardUserDefaults];
//NSString *acctNumber = [options stringForKey:@"accountNumber"];
//NSString *restrictKey = [options stringForKey:@"restrictKey"];
//uncomment for actual
//[request setPostValue:acctNumber forKey:@"ePNAccount"];
//[request setPostValue:restrictKey forKey:@"RestrictKey"];
if([strSaleType compare:@"Test"] == NSOrderedSame)
{
//FOR TESTING ONLY: UNCOMMENT ABOVE FOR ACTUAL ACCOUNT
[request setPostValue:@"080880" forKey:@"ePNAccount"];
[request setPostValue:@"yFqqXJh9Pqnugfr" forKey:@"RestrictKey"];
}
//FOR TESTING ONLY: UNCOMMENT ABOVE FOR ACTUAL ACCOUNT
[request setPostValue:@"080880" forKey:@"ePNAccount"];
[request setPostValue:@"yFqqXJh9Pqnugfr" forKey:@"RestrictKey"];
//transaction type
if([strSaleType compare:@"Sale"] == NSOrderedSame)
{
[request setPostValue:@"Sale" forKey:@"TranType"];
}
if([strSaleType compare:@"Refund"] == NSOrderedSame)
{
[request setPostValue:@"Return" forKey:@"TranType"];
}
if([strSaleType compare:@"Test"] == NSOrderedSame)
{
[request setPostValue:@"Sale" forKey:@"TranType"];
}
//request no HTML output
[request setPostValue:@"No" forKey:@"HTML"];
//needed to get transID for signature capture
[request setPostValue:@"report" forKey:@"Inv"];
//card number
[request setPostValue:txtCardNumber.text forKey:@"CardNo"];
//parse date
NSString *strDateFull = txtExpires.text;
NSString *strMonth = [strDateFull substringWithRange: NSMakeRange(0, 2)];
NSString *strYear = [strDateFull substringWithRange: NSMakeRange(3, 2)];
//expire month
[request setPostValue:strMonth forKey:@"ExpMonth"];
//expire year
[request setPostValue:strYear forKey:@"ExpYear"];
//total, send as you would write it. no dollar sign needed
[request setPostValue:txtGrandTotal.text forKey:@"Total"];
//address - this makes TBDE ignore requests with no address
[request setPostValue:@"1" forKey:@"SKIP_MISSING"];
//zip
[request setPostValue:txtZip.text forKey:@"Zip"];
//ccv2
[request setPostValue:@"CVV2Type" forKey:@"1"];
[request setPostValue:txtCCV2.text forKey:@"123"];
//email
[request setPostValue:txtEmail.text forKey:@"EMail"];
//invoice # - optional
[request setPostValue:txtInvoice.text forKey:@"Invoice"];
//blocking of course
[request start];
// get confirmation
confirmViewController *anotherViewController = [[confirmViewController alloc] initWithNibName:@"confirmView" bundle:nil];
//set properties
anotherViewController.strConfirmation = [request responseString];
anotherViewController.strCardNumber = txtCardNumber.text;
anotherViewController.strExpires = txtExpires.text;
anotherViewController.strAmount = txtGrandTotal.text;
[self.navigationController pushViewController:anotherViewController animated:YES];
//reset interface
if([anotherViewController.strApproval compare:@"""Y"] == NSOrderedSame)
{
txtCardNumber.text = @"";
txtExpires.text = @"";
txtGrandTotal.text = @"";
txtZip.text = @"";
txtCCV2.text = @"";
txtEmail.text = @"";
txtInvoice.text = @"";
}
[anotherViewController release];
/*
//display the results
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Info"
message:[request responseString]
delegate:nil
cancelButtonTitle:@"OK"
otherButtonTitles: nil];
[alert show];
[alert release];
*/
}
/*
// The designated initializer. Override if you create the controller programmatically and want to perform customization that is not appropriate for viewDidLoad.
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) {
// Custom initialization
}
return self;
}
*/
/*
开发者_高级运维// Implement loadView to create a view hierarchy programmatically, without using a nib.
- (void)loadView {
}
*/
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
[super viewDidLoad];
//Needed to get events
[txtCardNumber setDelegate:self];
[txtExpires setDelegate:self];
[txtGrandTotal setDelegate:self];
[txtZip setDelegate:self];
[txtEmail setDelegate:self];
[txtCCV2 setDelegate:self];
[txtInvoice setDelegate:self];
//adjust title depending on sale type
if([strSaleType compare:@"Sale"] == NSOrderedSame)
{
self.title = @"Sales";
NSLog(@"Passed in sale type: %@", strSaleType );
}
if([strSaleType compare:@"Refund"] == NSOrderedSame)
{
self.title = @"Refunds";
NSLog(@"Passed here in sale type: %@", strSaleType );
}
if([strSaleType compare:@"Test"] == NSOrderedSame)
{
self.title = @"Testing";
NSLog(@"Passed in sale type: %@", strSaleType );
}
//add additional button
UIBarButtonItem *submitButton = [[UIBarButtonItem alloc] initWithTitle:@"Submit" style:UIBarButtonItemStylePlain target:self action:@selector(btnSubmitClicked)];
self.navigationItem.rightBarButtonItem = submitButton;
[submitButton release];
}
- (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 {
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)dealloc {
if(txtCardNumber != NULL)
{
[txtCardNumber release];
}
if(txtExpires != NULL)
{
[txtExpires release];
}
if(txtGrandTotal != NULL)
{
[txtGrandTotal release];
}
if(txtZip != NULL)
{
[txtZip release];
}
if(txtEmail != NULL)
{
[txtEmail release];
}
if(txtCCV2 != NULL)
{
[txtCCV2 release];
}
if(txtInvoice != NULL)
{
[txtInvoice release];
}
if(strSaleType != NULL)
{
[strSaleType release];
}
[super dealloc];
}
@end
#import "confirmViewController.h"
@implementation confirmViewController
@synthesize lblStatus;
@synthesize lblCardType;
@synthesize lblCardNumber;
@synthesize lblExpires;
@synthesize lblAmount;
@synthesize lblApproval;
@synthesize strConfirmation;
@synthesize strCardNumber;
@synthesize strExpires;
@synthesize strAmount;
@synthesize strApproval;
-(void)btnSignatureClicked
{
sigCaptureViewController *anotherViewController = [[sigCaptureViewController alloc] initWithNibName:@"sigCaptureView" bundle:nil];
[self.navigationController pushViewController:anotherViewController animated:YES];
[anotherViewController release];
}
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
[super viewDidLoad];
//prepare confirmation, all that is needed is the first string
NSArray *strings = [strConfirmation componentsSeparatedByString: @","];
NSString *strPreParsed = [strings objectAtIndex:0];
//break out yes/no so we can set status
//NSString *strYesNO = [strPreParsed substringToIndex:2];
NSString *strYesOrNo = [strPreParsed substringWithRange: NSMakeRange(1, 1)];
//save approval for later
strApproval = strYesOrNo;
//debug
NSLog(@"strNo= %@",strYesOrNo);
NSLog(@"strPreParsed= %@", strPreParsed);
//set results
if([strYesOrNo compare:@"Y"] == NSOrderedSame)
{
lblStatus.text = @"Approved";
lblStatus.textColor = [UIColor greenColor];
}
if([strYesOrNo compare:@"N"] == NSOrderedSame)
{
lblStatus.text = @"Declined";
lblStatus.textColor = [UIColor redColor];
}
if([strYesOrNo compare:@"U"] == NSOrderedSame)
{
lblStatus.text = @"Try Again";
lblStatus.textColor = [UIColor redColor];
}
//set card type
if([lblCardNumber.text compare:@"4"] == NSOrderedSame)
{
lblCardType.text = @"Visa";
}
if([lblCardNumber.text compare:@"5"] == NSOrderedSame)
{
lblCardType.text = @"Master";
}
if([lblCardNumber.text compare:@"6"] == NSOrderedSame)
{
lblCardType.text = @"Discover";
}
//set cardnumber
lblCardNumber.text = strCardNumber;
//set expires
lblExpires.text = strExpires;
//set amount
lblAmount.text = strAmount;
//set approval string
lblApproval.text = strPreParsed;
//add signature button
UIBarButtonItem *signatureButton = [[UIBarButtonItem alloc] initWithTitle:@"Signature" style:UIBarButtonItemStylePlain target:self action:@selector(btnSignatureClicked)];
self.navigationItem.rightBarButtonItem = signatureButton;
[signatureButton release];
//set title
self.title = @"Approval";
}
- (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 {
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)dealloc {
if(lblCardType != NULL)
{
[lblCardType release];
}
if(lblCardNumber != NULL)
{
[lblCardNumber release];
}
if(lblExpires != NULL)
{
[lblExpires release];
}
if(lblAmount != NULL)
{
[lblAmount release];
}
if(lblApproval != NULL)
{
[lblApproval release];
}
if(lblStatus != NULL)
{
[lblStatus release];
}
if(strConfirmation != NULL)
{
[strConfirmation release];
}
if(strCardNumber != NULL)
{
[strCardNumber release];
}
if(strExpires != NULL)
{
[strExpires release];
}
if(strAmount != NULL)
{
[strAmount release];
}
if(strApproval != NULL)
{
[strApproval release];
}
[super dealloc];
}
@end
I think you are releasing properties that should not be released, for instance you create strYesOrNo like this:
NSString *strYesOrNo = [strPreParsed substringWithRange: NSMakeRange(1, 1)];
without allocating the string. So the string belongs to the viewDidLoad function and will be released by this function. But after creating the strYesOrNo you assign it to a class property, like this:
strApproval = strYesOrNo;
By the time you dealloc your viewcontroller you try to release strApproval, but the viewDidLoad allready released this value and you get a bad-access. You can solve this problem by allocating the memory for strApproval like:
strApproval = [[NSString alloc] initWithString:strYesOrNo];
I did not go through all your code so maybe this is also true for some other properties. Hope this helped.
精彩评论