开发者

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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜