Discussion in 'iOS Programming' started by ppn, Oct 31, 2010.

  1. ppn macrumors member

    Oct 31, 2010
    I'm getting this exc_bad_access error. I did some research into this error and this error means I'm over releasing something but I don't know what I'm over releasing. I think it's something to do with the NSMutableArray that I have in the code. If I comment out the following line, I don't get the error but I don't get any data from core data either.

    self.quizzes = [[managedObjectContext_ executeFetchRequest:request error:&error] mutableCopy];
    Here's my complete QuizViewController.h code:

    @protocol QuizViewControllerDelegate;
    @interface QuizViewController : UIViewController  {
    	id <QuizViewControllerDelegate> delegate;
    	IBOutlet UIImageView *image;
    	IBOutlet UILabel *questionNumber;
    	IBOutlet UILabel *question;
    	IBOutlet UILabel *solution;
    	IBOutlet UIButton *answerA;
    	IBOutlet UIButton *answerB;
    	IBOutlet UIButton *answerC;
    	IBOutlet UIButton *answerD;
    	IBOutlet UIButton *next;
    	NSInteger counter;
    	NSInteger correctCounter;
    	NSManagedObjectContext *managedObjectContext_;
    	NSMutableArray *quizzes;
    	Quiz *currentQuiz;
    @property (nonatomic, assign) id <QuizViewControllerDelegate> delegate;
    @property (nonatomic, retain) UIImageView *image;
    @property (nonatomic, retain) UILabel *questionNumber;
    @property (nonatomic, retain) UILabel *question;
    @property (nonatomic, retain) UILabel *solution;
    @property (nonatomic, retain) UIButton *answerA;
    @property (nonatomic, retain) UIButton *answerB;
    @property (nonatomic, retain) UIButton *answerC;
    @property (nonatomic, retain) UIButton *answerD;
    @property (nonatomic, retain) UIButton *next;
    @property (nonatomic, assign) NSInteger counter;
    @property (nonatomic, assign) NSInteger correctCounter;
    @property (nonatomic, retain) NSManagedObjectContext *managedObjectContext_;
    @property (nonatomic, retain) NSMutableArray *quizzes;
    @property (nonatomic, readonly) Quiz *currentQuiz;
    - (IBAction)done:(id)sender;
    - (IBAction)checkAnswer:(id)sender;
    - (IBAction)nextQuestion:(id)sender;
    - (void)exitQuizOnError;
    - (void)completeQuizAlert;
    @protocol QuizViewControllerDelegate
    - (void)quizViewControllerDidFinish:(QuizViewController *)quiz;
    And here's my QuizViewController.m code

    @implementation QuizViewController
    @synthesize delegate;
    @synthesize image;
    @synthesize questionNumber, solution, question;
    @synthesize answerA, answerB, answerC, answerD, next;
    @synthesize counter, correctCounter;
    @synthesize managedObjectContext_;
    @synthesize quizzes;
    - (Quiz *) currentQuiz {
    	if (self.counter < 0) {
    		return nil;
    	Quiz *quiz = [self.quizzes objectAtIndex:(self.counter - 1)];
    	return quiz;
     // 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 viewDidLoad to do additional setup after loading the view, typically from a nib.
    - (void)viewDidLoad {
    	counter = 1;
    	correctCounter = 1;
    	NSFetchRequest *request = [[NSFetchRequest alloc] init];
    	//this is needed because QuizViewController isn't the first level view. The managedObjectContext was nil before this declaration
    	if (self.managedObjectContext_ == nil) {
    		self.managedObjectContext_ = [(OntarioG1TestAppDelegate *)[[UIApplication sharedApplication] delegate]managedObjectContext]; 
    	NSEntityDescription *entity = [NSEntityDescription entityForName:@"Quiz"
    	[request setEntity:entity];
    	NSError *error;
    	self.quizzes = [[managedObjectContext_ executeFetchRequest:request error:&error] mutableCopy];
    	[request release];
    	[self nextQuestion:self];
    	[super viewDidLoad];
    -(IBAction)done:(id)sender {
    	[self.delegate quizViewControllerDidFinish:self];
    	if (counter==20) {
    		[self completeQuizAlert];
    	} else {
    		NSString *tempSolution;
    		NSString *tempCorrect = @"Yes, you're right! The answer is: \n";
    		NSString *tempWrong = @"No, the correct answer is: \n";
    		NSString *finalSolution;
    		UIButton *button = (UIButton *)sender;
    		if ([self.currentQuiz.solution intValue] == 1) {
    			tempSolution = self.currentQuiz.answerA;
    		} else if ([self.currentQuiz.solution intValue] == 2) {
    			tempSolution = self.currentQuiz.answerB;
    		} else if ([self.currentQuiz.solution intValue] == 3) {
    			tempSolution = self.currentQuiz.answerC;
    		} else {
    			tempSolution = self.currentQuiz.answerD;
    		if ([self.currentQuiz.solution intValue] == button.tag) {
    			finalSolution = [[NSString alloc] initWithFormat:@"%@ %@", tempCorrect, tempSolution];
    		} else {
    			finalSolution = [[NSString alloc] initWithFormat:@"%@ %@", tempWrong, tempSolution];
    		solution.text = finalSolution;
    		[tempSolution release];
    		[tempCorrect release];
    		[tempWrong release];
    		[finalSolution release];
    		answerA.hidden = YES;
    		answerB.hidden = YES;
    		answerC.hidden = YES;
    		answerD.hidden = YES;
    		next.hidden = NO;
    		solution.hidden = NO;
    		NSString *temp = [[NSString alloc]initWithFormat:@"Q: %i/20", counter];
    		questionNumber.text = temp;
    		[temp release];
    	if ([self.currentQuiz.images isEqualToString:@""]) {
    		self.question.frame = CGRectMake(self.question.frame.origin.x, 30, self.question.frame.size.width, 130);
    		self.answerA.frame = CGRectMake(self.question.frame.origin.x, 133, self.question.frame.size.width, 60);
    		self.answerB.frame = CGRectMake(self.question.frame.origin.x, 201, self.question.frame.size.width, 60);
    		self.answerC.frame = CGRectMake(self.question.frame.origin.x, 269, self.question.frame.size.width, 60);
    		self.answerD.frame = CGRectMake(self.question.frame.origin.x, 337, self.question.frame.size.width, 60);
    		image.hidden = YES;
    	} else {
    		self.question.frame = CGRectMake(self.question.frame.origin.x, 190, self.question.frame.size.width, 65);
    		self.answerA.frame = CGRectMake(self.question.frame.origin.x, 253, self.question.frame.size.width, 45);
    		self.answerB.frame = CGRectMake(self.question.frame.origin.x, 306, self.question.frame.size.width, 45);
    		self.answerC.frame = CGRectMake(self.question.frame.origin.x, 359, self.question.frame.size.width, 45);
    		self.answerD.frame = CGRectMake(self.question.frame.origin.x, 412, self.question.frame.size.width, 45);
    		image.hidden = NO;
    		//[images setImage:self.currentQuiz.images];
    	question.text = self.currentQuiz.question;
    	[answerA setTitle:self.currentQuiz.answerA forState:UIControlStateNormal];
    	[answerB setTitle:self.currentQuiz.answerB forState:UIControlStateNormal];
    	[answerC setTitle:self.currentQuiz.answerC forState:UIControlStateNormal];
    	[answerD setTitle:self.currentQuiz.answerD forState:UIControlStateNormal];
    	answerA.hidden = NO;
    	answerB.hidden = NO;
    	answerC.hidden = NO;
    	answerD.hidden = NO;
    	next.hidden = YES;
    	solution.hidden = YES;
    #pragma mark -
    #pragma mark Alert 
    -(void)exitQuizOnError {
    	UIAlertView *alertDialog = [[UIAlertView alloc] initWithTitle:@"Error" 
    														  message:@"An error occurred with the quiz. Please restart the quiz." 
    	[alertDialog show];
    	[alertDialog release];
    -(void)completeQuizAlert {
    	UIAlertView *alertDialog;
    	NSString *tempMessage;
    	if (correctCounter < 16) {
    		tempMessage = [[NSString alloc] initWithFormat:@"Sorry you've failed your test. Your score is %i/20. Do you want to try again?", correctCounter];
    	} else {
    		tempMessage = [[NSString alloc] initWithFormat:@"Congratulations!! You passed your test. Your score is %i/20. Do you want to try again?", correctCounter];
    		alertDialog = [[UIAlertView alloc]
    				   initWithTitle:@"Quiz Completed!"
    				   message: tempMessage
    				   otherButtonTitles:@"No", nil];
    	[alertDialog show];
    	[alertDialog release];
    	[tempMessage release];
    -(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
    	if (buttonIndex == 0)
    		counter = 1;
    		questionNumber.text = @"Q: 1/20";
    	else {
    		[self done:self];
    #pragma mark -
    // Override to allow orientations other than the default portrait orientation.
    - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
        // Return YES for supported orientations
        return (interfaceOrientation == UIInterfaceOrientationPortrait);
    - (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 {
        [super viewDidUnload];
        // Release any retained subviews of the main view.
        // e.g. self.myOutlet = nil;
    - (void)dealloc {
    	[image release];
    	[questionNumber release];
    	[question release];
    	[solution release];
    	[answerA release];
    	[answerB release];
    	[answerC release];
    	[answerD release];
    	[next release];
    	[managedObjectContext_ release];
    	[quizzes release];
            [super dealloc];
  2. PhoneyDeveloper macrumors 68040


    Sep 2, 2008
    It looks like you are releasing tempSolution when you shouldn't be. Releasing tempCorrect and tempWrong is also incorrect but won't cause a crash. You need to understand the memory management rules (better).

    Any kind of bad access crash or other crash will happen at a particular line of code when run in the debugger. In most cases there are clues regarding the cause of the error in the debugger. You need to use the debugger to figure these things out.
  3. ppn thread starter macrumors member

    Oct 31, 2010
    Wow, amazing! That fixed my code. So does it mean if I don't retain it, I don't have to release it? I'm still starting out so I get confused on what I need to release and what I don't need to release.
  4. PhoneyDeveloper macrumors 68040


    Sep 2, 2008
    With your new-found knowledge you should re-read the memory management guide.

    If you don't retain it (or have it retained for you) then of course you don't release it since you don't own it. You need to read the memory management guide to see the cases where an object is retained by you even if you don't explicitly call retain on it.
  5. ppn thread starter macrumors member

    Oct 31, 2010

Share This Page