tableView crashes when going back from detail view iphone
in my application i have a table view and a detail view. The table view is populated from a database query. I have this database methods in the viewDidLoad
method (i don't know where else to put it) Then i have the [self.tableView reload]
method in the viewWillAppear
method. The problem is that when i go back from the detail view to the table view and click the same element (in the table view) the application crashes. I guess it is because the database methods are still running when i come back from the detail view and i click on a cell. So the data in the table view is never reloaded. Do you guys have any idea on how to fix this?
*EDIT: *Here's the code from the database, i use it to populate the table view:*
- (void)viewDidLoad
{
//Convert the course id to string
NSString *selectedCategoryIdConverted = [NSString stringWithFormat:@"%d", self.selectedCategory._id];
NSMutableArray *tempArray = [[NSMutableArray alloc]init];
// Set up sqlite statement
sqlite3_stmt *dbStatement = nil;
NSString *sqlQuery = [NSString stringWithFormat:@"SELECT co.name, co.id, o.location FROM course as co JOIN categories as ca JOIN occasions as o WHERE co.catID = ca.id AND co.catID = %i AND o.courseID = co.id", self.selectedCategory._id];
//Convert the query string to const char
const char *sqlQueryConverted =[sqlQuery UTF8String];
int prepareSqlQuery = sqlite3_prepare_v2( [[DatabaseController sharedDatabaseController] getDb], sqlQueryConverted, -1, &dbStatement, NULL);
//Run the query
while ( sqlite3_step(dbStatement) == SQLITE_ROW )
{
const char *name = (const char *)sqlite3_column_text(dbStatement, 0);
int courseId = sqlite3_column_int(dbStatement, 1);
const char *location = (const char *)sqlite3_column_text(dbStatement, 2);
//Convert the returnedElement char to string
NSString *nameConverted = [[[NSString alloc] initWithUTF8String:name] autorelease];
NSString *locationConverted = [[[NSString alloc] initWithUTF8String:location] autorelease];
Course *course = [[Course alloc] initWithName:nameConverted _id:courseId location:locationConverted];
[tempArray addObject:course];
}
self.courses = tempArray;
[super viewDidLoad];
}
EDIT: I noticed that when i go back to the table view, the app won't crash if i click on the next element, but if i click on the previous element (row) in the table view the app crashes.
EDIT: I changed the code to the viewDidAppear
method and fixed memory leaking. self.courses
is (nonatomic, retain)
here's the code:
- (void)viewWillAppear:(BOOL)animated
{
//Convert the course id to string
//NSString *selectedCategoryIdConverted = [NSString stringWithFormat:@"%d", self.selectedCategory._id];
NSMutableArray *tempArray = [[NSMutableArray alloc]init];
// Set up sqlite statement
sqlite3_stmt *dbStatement = nil;
NSString *sqlQuery = [NSString stringWithFormat:@"SELECT co.name, co.id, o.location FROM course as co JOIN categories as ca JOIN occasions as o WHERE co.catID = ca.id AND co.catID = %i AND o.courseID = co.id", self.selectedCategory._id];
//Convert the query string to const char
const char *sqlQueryConverted =[sqlQuery UTF8String];
int prepareSqlQuery = sqlite3_prepare_v2( [[DatabaseController sharedDatabaseController] getDb], sqlQueryConverted, -1, &dbStatement, NULL);
//Run the query
while ( sqlite3_step(dbStatement) == SQLITE_ROW )
{
const char *name = (const char *)sqlite3_column_text(dbStatement, 0);
int courseId = sqlite3_column_int(dbStatement, 1);
const char *location = (const char *)sqlite3_column_text(dbStatement, 2);
//Convert the returnedElement char to string
NSString *nameConverted = [[[NSString alloc] initWithUTF8String:name] autorelease];
NSString *locationConverted = [[[开发者_运维技巧NSString alloc] initWithUTF8String:location] autorelease];
Course *course = [[Course alloc] initWithName:nameConverted _id:courseId location:locationConverted];
[tempArray addObject:course];
[course release];
course = nil;
}
self.courses = tempArray;
[tempArray release];
[self.tableView reloadData];
[super viewWillAppear:animated];
}
EDIT: Here's is the error log:
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[UIDeviceWhiteColor _id]: unrecognized selector sent to instance 0x4d2e2a0'
Call stack at first throw:
(
0 CoreFoundation 0x010435a9 __exceptionPreprocess + 185
1 libobjc.A.dylib 0x01197313 objc_exception_throw + 44
2 CoreFoundation 0x010450bb -[NSObject(NSObject) doesNotRecognizeSelector:] + 187
3 CoreFoundation 0x00fb4966 ___forwarding___ + 966
4 CoreFoundation 0x00fb4522 _CF_forwarding_prep_0 + 50
5 BookApp 0x000079e8 -[CoursesCategoriesViewController viewWillAppear:] + 184
6 UIKit 0x0017c9be -[UINavigationController _startTransition:fromViewController:toViewController:] + 858
7 UIKit 0x0017732a -[UINavigationController _startDeferredTransitionIfNeeded] + 266
8 UIKit 0x0017e562 -[UINavigationController pushViewController:transition:forceImmediate:] + 932
9 UIKit 0x001771c4 -[UINavigationController pushViewController:animated:] + 62
10 BookApp 0x000056d6 -[CoursesViewController tableView:didSelectRowAtIndexPath:] + 374
11 UIKit 0x00135b68 -[UITableView _selectRowAtIndexPath:animated:scrollPosition:notifyDelegate:] + 1140
12 UIKit 0x0012bb05 -[UITableView _userSelectRowAtPendingSelectionIndexPath:] + 219
13 Foundation 0x0084579e __NSFireDelayedPerform + 441
14 CoreFoundation 0x010248c3 __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__ + 19
15 CoreFoundation 0x01025e74 __CFRunLoopDoTimer + 1220
16 CoreFoundation 0x00f822c9 __CFRunLoopRun + 1817
17 CoreFoundation 0x00f81840 CFRunLoopRunSpecific + 208
18 CoreFoundation 0x00f81761 CFRunLoopRunInMode + 97
19 GraphicsServices 0x012d81c4 GSEventRunModal + 217
20 GraphicsServices 0x012d8289 GSEventRun + 115
21 UIKit 0x000ccc93 UIApplicationMain + 1160
22 BookApp 0x00001ff9 main + 121
23 BookApp 0x00001f75 start + 53
)
terminate called after throwing an instance of 'NSException'
From your stack trace, the interesting parts are :
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[UIDeviceWhiteColor _id]: unrecognized selector sent to instance 0x4d2e2a0'
and
5 BookApp 0x000079e8 -[CoursesCategoriesViewController viewWillAppear:] + 184
which corresponds to :
- (void)viewWillAppear:(BOOL)animated {
//...
NSString *sqlQuery =
[NSString stringWithFormat:
@"SELECT co.name, co.id, o.location FROM course as co JOIN categories as ca JOIN occasions as o WHERE co.catID = ca.id AND co.catID = %i AND o.courseID = co.id",
self.selectedCategory._id]; // << The culprit
//...
You get this because self.selectedCategory._id
tries to send an _id
message to self.selectedCategory
and fails, self.selectedCategory
not being the good type.
How could this be possible?
Since I guess you are sure that self.selectedCategory
is the expected type...
Simply because self.selectedCategory
has been released, and its address has been reused for another variable... of another type, in your trace a UIColor instance... Could be anything else.
Conclusion
Double check your retain
/release
of that self.selectedCategory
property :)
Side note
+1 for the FMDB
suggestion... A must!
Your code is leaking memory. You are not putting release after assigning temp array to self.courses. Also you are not releasing course object after adding it to temp array. For SQLite operations I suggest you to use FMDB. It will be very easier to manage then putting SQL queries in each view controller to fetch the data from database. Also It's a bad practice to follow this kind of pattern. Use FMDB for all your sqlite purpose. Create a seperate class for all the sqlite communication.
精彩评论