views:

420

answers:

3

I have been banging my head against the wall for a couple days and need some help. I have a feeling that I am doing something really silly here, but I cannot find the issue. This is the controller for a table view. I put the SQL in line to simplify it as part of the troubleshooting of this error. Normally, it would be in an accessor method in a model class.

It gets through the SQL read just fine. Finds the two objects, loads them into the todaysWorkout array and then builds the cells for the table view. The table view actually comes up on the scree and then it throws the EXC_BAD_ACCESS.

I ran instruments and it shows the following:

0 CFString Malloc 1 00:03.765 0x3946470 176 Foundation -[NSPlaceholderString initWithFormat:locale:arguments:]

1 CFString Autorelease 00:03.765 0x3946470 0 Foundation NSRecordAllocationEvent

2 CFString CFRelease 0 00:03.767 0x3946470 0 Bring It -[WorkoutViewController viewDidLoad]

3 CFString Zombie -1 00:03.917 0x3946470 0 Foundation NSPopAutoreleasePool

Here is the source code for the controller. I left it all in there just in case there is something extraneous causing the problem. I sincerely appreciate any help I can get:

HEADER:

#import <UIKit/UIKit.h>
#import <sqlite3.h>
#import "NoteCell.h"
#import "BIUtility.h"
#import "Bring_ItAppDelegate.h"
#import "MoveListViewController.h"


@class MoveListViewController;
@class BIUtility;

@interface WorkoutViewController : UITableViewController {
    NSMutableArray *todaysWorkouts;
    IBOutlet NoteCell *woNoteCell;
    MoveListViewController *childController;
    NSInteger scheduleDay;
    BIUtility *bi;
}

@property (nonatomic, retain) NSMutableArray *todaysWorkouts;
@property (nonatomic, retain) NoteCell *woNoteCell;
@property (nonatomic,retain) BIUtility *bi;

//@property (nonatomic, retain) SwitchCell *woSwitchCell;

@end

CLASS:

#import "WorkoutViewController.h"
#import "MoveListViewController.h"
#import "Profile.h"

static sqlite3 *database = nil;

@implementation WorkoutViewController
@synthesize todaysWorkouts;
@synthesize woNoteCell;
@synthesize bi;

//@synthesize woSwitchCell;


- (void)viewDidLoad {
    [super viewDidLoad];


 bi = [[BIUtility alloc] init];


 todaysWorkouts = [[NSMutableArray alloc] init];

 NSString *query;
 sqlite3_stmt *statement;

 //open the database
 if (sqlite3_open([[BIUtility getDBPath] UTF8String], &database) != SQLITE_OK) {
  sqlite3_close(database);
  NSAssert(0, @"Failed to opendatabase");
 }

 query = [NSString stringWithFormat:@"SELECT IWORKOUT.WOINSTANCEID, IWORKOUT.WORKOUTID, CWORKOUTS.WORKOUTNAME FROM CWORKOUTS JOIN IWORKOUT ON IWORKOUT.WORKOUTID = CWORKOUTS.WORKOUTID AND DATE = '%@'", [BIUtility todayDateString]];
 if (sqlite3_prepare_v2(database, [query UTF8String], -1, &statement, nil) == SQLITE_OK) {
  while (sqlite3_step(statement) == SQLITE_ROW) {
   Workout *wo = [[Workout alloc] init];
   wo.woInstanceID = sqlite3_column_int(statement, 0);
   wo.workoutID = sqlite3_column_int(statement, 1);
   wo.workoutName = [NSString stringWithUTF8String:(char *)sqlite3_column_text(statement, 2)];
   [todaysWorkouts addObject:wo];    
   [wo release];    
  }
  sqlite3_finalize(statement);

 } 
 if(database) sqlite3_close(database);

 [query release];




}



- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
 //todaysWorkouts = [BIUtility todaysScheduledWorkouts];
 static NSString *noteCellIdentifier = @"NoteCellIdentifier";

 UITableViewCell *cell;


 if (indexPath.section < ([todaysWorkouts count])) {
  cell = [tableView dequeueReusableCellWithIdentifier:@"OtherCell"];
  if (cell == nil) {
   cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier: @"OtherCell"] autorelease];
   cell.accessoryType = UITableViewCellAccessoryNone;
  } 
  if (indexPath.row == 0) {
   Workout *wo = [todaysWorkouts objectAtIndex:indexPath.section];   
   [cell.textLabel setText:wo.workoutName];
  } else {
   [cell.textLabel setText:@"Completed?"];
   [cell.textLabel setFont:[UIFont fontWithName:@"Arial" size:15]];
   [cell.textLabel setTextColor:[UIColor blueColor]];
  }

 } else { 
  cell = (NoteCell *)[tableView dequeueReusableCellWithIdentifier:noteCellIdentifier];
  if (cell == nil) {
   NSArray *nib = [[NSBundle mainBundle] loadNibNamed:@"NoteCell" owner:self options:nil];
   cell = [nib objectAtIndex:0];
  }
 }


 return cell; 

 //[cell release];
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
 NSUInteger row = [indexPath row];

 if (indexPath.section < ([todaysWorkouts count]) && (row == 0)) {
  MoveListViewController *moveListController = [[MoveListViewController alloc] initWithStyle:UITableViewStylePlain];
  moveListController.workoutID = [[todaysWorkouts objectAtIndex:indexPath.section] workoutID];
  moveListController.workoutName = [[todaysWorkouts objectAtIndex:indexPath.section] workoutName];
  moveListController.woInstanceID = [[todaysWorkouts objectAtIndex:indexPath.section] woInstanceID];


  NSLog(@"Workout Selected: %@", [[todaysWorkouts objectAtIndex:indexPath.section] workoutName]);
  Bring_ItAppDelegate *delegate = [[UIApplication sharedApplication] delegate];
  [delegate.workoutNavController pushViewController:moveListController animated:YES];
 } else {


  UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath]; 
  if (indexPath.section < ([todaysWorkouts count]) && (row == 1)) {
   if (cell.accessoryType == UITableViewCellAccessoryNone) {
    cell.accessoryType = UITableViewCellAccessoryCheckmark;
   }
   else {
    cell.accessoryType = UITableViewCellAccessoryNone;
   }
  }
 }
 [tableView deselectRowAtIndexPath:indexPath animated:YES];
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
 NSInteger h = 35;
 return h;
}

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
 return ([todaysWorkouts count] + 1);
 //return ([todaysWorkouts count]);

}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {

 if (section < ([todaysWorkouts count])) {
  return 2;
 } else { 
  return 1;
 }


}

- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {

 if (section < ([todaysWorkouts count])) {
  return @"Workout";
 } else { 
  return @"How Was Your Workout?";
 }

}


- (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 {
    [todaysWorkouts release];
 [bi release];
 [super dealloc];
}


@end
+3  A: 

You are releasing query, but it is marked as autorelease by the stringWithFormat method.

When the run loop comes around to release it again, it had already been released by your code, thus throwing the EXC_BAD_ACCESS exception.

Only release objects that you retain, copy, alloc, or new.

Alex
OMG - It was silly. Thanks so much. I got a little release happy. I really appreciate your help.
Michael Bordelon
A: 

Culprit line:

NSString *query;
query = [NSString stringWithFormat:@"SELECT IWORKOUT.WOINSTANCEID, IWORKOUT.WORKOUTID, CWORKOUTS.WORKOUTNAME FROM CWORKOUTS JOIN IWORKOUT ON IWORKOUT.WORKOUTID = CWORKOUTS.WORKOUTID AND DATE = '%@'", [BIUtility todayDateString]];
[query release];

query is not being retained, yet you are releasing it. When the autorelease pool releases it, you are going to stumble upon an EXC_BAD_ACCESS error for over-releasing.

meeselet
A: 

The following line creates an autoreleased NSString with a retain count of 1

query = [NSString stringWithFormat:@"SELECT IWORKOUT.WOINSTANCEID, IWORKOUT.WORKOUTID, CWORKOUTS.WORKOUTNAME FROM CWORKOUTS JOIN IWORKOUT ON IWORKOUT.WORKOUTID = CWORKOUTS.WORKOUTID AND DATE = '%@'", [BIUtility todayDateString]]; 

When you then do

[query release];

The retain count of query will be 0 and so it will be deallocated. But there is still a reference to it in the auto release pool. Then, when the auto release pool is drained later on, it tries to do

[query release];

as well. And since the object was already deallocated and the pointer is now invalid, you get EXC_BAD_ACCESS.

Toon Van Acker