SQLite and UITableView: Crash after numberOfRowsInSection
First I would like to make clear that I do not want to use Core Data in
this case.
My Problem: whenever my tableview's delegate methodd:
numberOfRowsInSection is called, the application crashes with nothing more
than an (lldb) error message.
First I have two classes which helps me retrieve rows from my SQLite
database.
sqlite.m:
#import "sqlite.h"
#import <sqlite3.h>
@implementation sqlite
@synthesize carbohydrates = _carbohydrates;
@synthesize name = _name;
@synthesize fat = _fat;
@synthesize kcal = _kcal;
- (id)initWithName:(NSString *)name2 carbs:(NSNumber *)carbs2
fat:(NSNumber *)fat2 kcal:(NSNumber*)kcal2 {
if ((self = [super init])) {
self.carbohydrates = carbs2;
self.name = name2;
self.fat = fat2;
self.kcal = kcal2;
}
return self;
}
- (void) dealloc {
self.name = nil;
self.kcal = nil;
self.fat = nil;
self.carbohydrates = nil;
[super dealloc];
}
@end
NutritionsDB.m:
#import "NutritionsDB.h"
#import "sqlite.h"
@implementation NutritionsDB
static NutritionsDB *_database;
+ (NutritionsDB*)database {
if (_database == nil) {
_database = [[NutritionsDB alloc] init];
}
return _database;
}
- (id)init {
if ((self = [super init])) {
NSString *sqLiteDb = [[NSBundle mainBundle]
pathForResource:@"Livsmedeldatabas"
ofType:@"sqlite"];
if (sqlite3_open([sqLiteDb UTF8String], &_database) != SQLITE_OK) {
NSLog(@"Failed to open database!");
}
}
return self;
}
- (void)dealloc {
sqlite3_close(_database);
[super dealloc];
}
-(void)setUpDB{
const char *sql_stmt = "CREATE INDEX IF NOT EXISTS name_index on
livsmedel(namn)";
char *errMsg;
if (sqlite3_exec(_database, sql_stmt, NULL, NULL, &errMsg) == SQLITE_OK)
{
puts("Index successfully created");
// SQL statement execution succeeded
}
}
-(NSArray*)sqliteInfo:(NSString*)predicateString{
NSMutableArray *retval = [[[NSMutableArray alloc] init] autorelease];
sqlite3_stmt *statement;
if (sqlite3_prepare_v2(_database, [predicateString
cStringUsingEncoding:NSUTF8StringEncoding], -1, &statement, nil)
== SQLITE_OK) {
while (sqlite3_step(statement) == SQLITE_ROW) {
char *nameChars = (char *) sqlite3_column_text(statement, 0);
char *kcalchars = (char *) sqlite3_column_text(statement, 1);
char *fatchars = (char *) sqlite3_column_text(statement, 2);
char *carbchars = (char *) sqlite3_column_text(statement, 3);
NSLog(@"\n%s, \n%s, \n%s", kcalchars, fatchars, carbchars);
NSString *name = [[NSString alloc] initWithUTF8String:nameChars];
NSString *kcal = [NSString stringWithFormat:@"%s", kcalchars];
NSString *fat = [NSString stringWithFormat:@"%s", fatchars];
NSString *carb = [NSString stringWithFormat:@"%s", carbchars];
NSNumberFormatter * f = [[NSNumberFormatter alloc] init];
[f setNumberStyle:NSNumberFormatterDecimalStyle];
NSNumber * kcalNumber = [f numberFromString:kcal];
NSNumber * fatNumber = [f numberFromString:fat];
NSNumber * carbNumber = [f numberFromString:carb];
NSLog(@"\n kcalnum : %@, \n fatnum: %@, \n carbnum : %@",
kcalNumber, fatNumber, carbNumber);
[f release];
sqlite *info = [[sqlite alloc] initWithName:name
carbs:carbNumber fat:fatNumber kcal:kcalNumber] ;
NSLog(@"%@,%@,%@,%@", name, kcal, fat, carb);
[retval addObject:info];
[name release];
[kcal release];
[fat release];
[carb release];
}
sqlite3_finalize(statement);
}
return retval;
}
@end
Now, In one of my viewcontrollers, I continuously make database calls via
the method
-(NSArray*)sqliteInfo:(NSString*)predicateString.
predicateString is a copy of a text which the user enters in a search bar
inside the VC.
In addition to the UISearchBar, the VC also holds a UITableView to
represent the rows fetched from the databse.
Here is how I update the datasource contents and re-render the the table
view.
- (NSInteger)tableView:(UITableView *)tableView
numberOfRowsInSection:(NSInteger)section {
return self.nutritionList.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSLog(@"hej");
static NSString *CellIdentifier = @"NutritionIdentifier";
UITableViewCell *cell = [tableView
dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc]
initWithStyle:UITableViewCellStyleSubtitle
reuseIdentifier:CellIdentifier] autorelease];
}
cell.textLabel.font = [UIFont fontWithName:@"Avenir-Medium" size:18.0];
cell.textLabel.text = [(sqlite*)[self.nutritionList
objectAtIndex:indexPath.row] name];
return cell;
}
-(void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString
*)searchText{
[self.nutritionList removeAllObjects];
if (searchText.length < 2) {
;
} else {
NSString *firstChar = [searchText
substringWithRange:NSMakeRange(0, 1)];
if([firstChar isEqualToString:@"å"] ||
[firstChar isEqualToString:@"Å"] ||
[firstChar isEqualToString:@"ä"] ||
[firstChar isEqualToString:@"Ä"] ||
[firstChar isEqualToString:@"ö"] ||
[firstChar isEqualToString:@"Ö"]){
NSString *lowerString = [firstChar lowercaseString];
NSString *upperString = [firstChar uppercaseString];
NSString *newSearchText = [searchText
stringByReplacingCharactersInRange:NSMakeRange(0, 1)
withString:lowerString];
NSString *newSearchText_upper = [searchText
stringByReplacingCharactersInRange:NSMakeRange(0, 1)
withString:upperString];
NSString *formatString =
[[[[[@"'"stringByAppendingString:newSearchText]stringByAppendingString:@"%'"]
stringByAppendingString:@" OR namn
like'"]stringByAppendingString:newSearchText_upper]stringByAppendingString:@"%'
ORDER BY namn COLLATE NOCASE"];
NSArray *array = [[NutritionsDB database] sqliteInfo:[NSString
stringWithFormat:@"Select * from livsmedel where namn like
%@", formatString ]];
NSLog(@"%@",[NSString stringWithFormat:@"Select * from
livsmedel where namn like %@", formatString ] );
for (sqlite *info in array) {
[self.nutritionList addObject:info];
}
}else{
NSString *formatString =
[[@"'"stringByAppendingString:searchText]stringByAppendingString:@"%'
"];
NSArray *array = [[NutritionsDB database] sqliteInfo:[NSString
stringWithFormat:@"SELECT * FROM livsmedel WHERE namn LIKE
%@", formatString ]];
NSLog(@"%@",[NSString stringWithFormat:@"Select * from
livsmedel where namn like %@", formatString ] );
for (sqlite *info in array) {
[self.nutritionList addObject:info];
NSLog(@"carbs %@, fat %@, kcal %@", info.carbohydrates,
info.fat, info.kcal);
}
}
}
[self.tableView reloadData];
}
Finally the crash occurs after the numberOfRowsInSection method is called,
but before the cellForRowAtIndexPath is called. Somewhere between them.
The console says (lldb), nothing else. The view below is the assembly
instructions that indicates where the crash occurs. However, I do not now
how to interpret them.
My question: Why does this crash occur?
Thanks for your help.
No comments:
Post a Comment