I'm trying to do a small class to manage Sqlite. I want to store the data retrieved from the DB into an array of objects but get app crashed (BAD_ACCESS)
My code:
- (ArrayList *) execNonQuery: (char *) query {
#try {
sqlite3_stmt *sqlStat;
ArrayList *dataList;
if(sqlite3_prepare_v2(self->dbHandle, query, -1, &sqlStat, NULL) == SQLITE_OK) {
dataList = [[ArrayList alloc] init];
while (sqlite3_step(sqlStat) == SQLITE_ROW) {
NSMutableArray *list = [[NSMutableArray alloc] init];
for (int i = 0; i < sqlite3_column_count(sqlStat); i++) {
// CRASH
id data = (__bridge id)(sqlite3_column_value(sqlStat, i));
[list addObject: data];
}
[dataList addList:list];
}
}
sqlite3_finalize(sqlStat);
return dataList;
}
#catch (NSException *exception) {
NSLog(#"Excepción capturada: %#", [exception reason]);
return NULL;
}
}
I think the problem is when i try to do:
id data = (__bridge id)(sqlite3_column_value(sqlStat, i));
Note: The ArrayList Class is just NSMutableArray of NSMutableArray
Im noob in objective c, just learning... and sorry for spelling errors.
Best regards.
Related
I have a question regarding the predicate I am using in the following code
NSMutableArray *records = (__bridge NSMutableArray *)ABAddressBookCopyArrayOfAllPeople( addressBook );
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"record.phoneNumber contains %#",#"123"];
#try {
[records filterUsingPredicate:predicate];
}
#catch (NSException *exception) {
NSLog(#"%#",exception);
}
#finally {
//
}
The exception I get is:
[<__NSCFType 0x6e2c5e0> valueForUndefinedKey:]: this class is not key value coding-compliant for the key record.
I've been trying to find a guide on predicates for address book with no luck though. Any suggestions?
You can't filter the address book using NSPredicates. Additionally, phoneNumber is not a field of ABRecordRef. Users can have multiple phone numbers, so you need to inspect each one.
You would do something like this:
CFArrayRef people = ABAddressBookCopyArrayOfAllPeople(addressBook);
NSMutableArray *matchingPeople = [NSMutableArray array];
for (CFIndex i = 0; i < CFArrayGetCount(people); i++) {
ABRecordRef person = CFArrayGetValueAtIndex(people, i);
ABMultiValueRef phones = ABRecordCopyValue(person, kABPersonPhoneProperty);
int phoneNumbers = ABMultiValueGetCount(phones);
if (phoneNumbers > 0) {
for (CFIndex i = 0; i < phoneNumbers; i++) {
NSString *phone = (NSString *)CFBridgingRelease(ABMultiValueCopyValueAtIndex(phones, i));
if ([phone rangeOfString:#"123"].location != NSNotFound) {
[matchingPeople addObject:person];
break;
}
}
}
CFRelease(phones);
}
CFRelease(people);
Personally, I wouldn't add ABRecordRefs to the array--I'd create a value object that includes just the fields you want from the record and add that, so when you're done with the loop, you can ensure you don't have any dangling CFTypes.
while removing the runtime memory leaks in my iPad application , I came across this strange memory leak in NSObject+JSONSerializableSupport class in the following method
+ (id) deserializeJSON:(id)jsonObject {
id result = nil;
if ([jsonObject isKindOfClass:[NSArray class]]) {
//JSON array
result = [NSMutableArray array];
for (id childObject in jsonObject) {
[result addObject:[self deserializeJSON:childObject]];
}
}
else if ([jsonObject isKindOfClass:[NSDictionary class]]) {
//JSON object
//this assumes we are dealing with JSON in the form rails provides:
// {className : { property1 : value, property2 : {class2Name : {property 3 : value }}}}
NSString *objectName = [[(NSDictionary *)jsonObject allKeys] objectAtIndex:0];
Class objectClass = NSClassFromString([objectName toClassName]);
if (objectClass != nil) {
//classname matches, instantiate a new instance of the class and set it as the current parent object
result = [[[objectClass alloc] init] autorelease];
}
NSDictionary *properties = (NSDictionary *)[[(NSDictionary *)jsonObject allValues] objectAtIndex:0];
NSDictionary *objectPropertyNames = [objectClass propertyNamesAndTypes];
for (NSString *property in [properties allKeys]) {
NSString *propertyCamalized = [[self convertProperty:property andClassName:objectName] camelize];
if ([[objectPropertyNames allKeys]containsObject:propertyCamalized]) {
Class propertyClass = [self propertyClass:[objectPropertyNames objectForKey:propertyCamalized]];
[result setValue:[self deserializeJSON:[propertyClass deserialize:[properties objectForKey:property]]] forKey:propertyCamalized];
}
}
}
else {
//JSON value
result = jsonObject;
}
return result;
}
I am getting the memory leak on this line
[result setValue:[self deserializeJSON:[propertyClass deserialize:[properties objectForKey:property]]] forKey:propertyCamalized];
Please suggest a solution or tell me where i am going wrong.
I am making a small iPhone application in which I have implemented the database concept which is used to store name, contact no, email id. I Want that whenever I user save any contact It get displayed on table view. In -(IBAction)retriveall:(id)sender action I am retriving all the data from database and storing it into array. Now I want to display all the data in tableview.
How can I do this? Please help me.
-(IBAction)retriveall:(id)sender
{
[self retrive2];
for (int i =0; i< [namearray count]; i++)
{
NSLog(#"Name is:%#",[namearray objectAtIndex:i]);
NSLog(#"Password is:%#",[passarray objectAtIndex:i]);
}
}
-(IBAction)retrive:(id)sender
{
[self retrive1];
two.text = databasecolorvalue;
UIAlertView *favAlert=[[UIAlertView alloc] initWithTitle:#"" message:#"Retrived" delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
[favAlert show];
[favAlert release];
}
-(void)retrive1
{
databaseName = #"med.sqlite";
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDir = [documentPaths objectAtIndex:0];
databasePath = [documentsDir stringByAppendingPathComponent:databaseName];
#try {
if(sqlite3_open([databasePath UTF8String], &database) == SQLITE_OK) {
const char *sqlStatement="select pswd from Login where username = ? ";
sqlite3_stmt *compiledStatement;
if(sqlite3_prepare_v2(database, sqlStatement, -1, &compiledStatement, NULL) == SQLITE_OK) {
// Loop through the results and add them to the feeds array
// Create a new animal object with the data from the database
sqlite3_bind_text(compiledStatement, 1, [one.text UTF8String], -1, SQLITE_TRANSIENT);
while(sqlite3_step(compiledStatement) == SQLITE_ROW) {
databasecolorvalue =[NSString stringWithUTF8String:(char*)sqlite3_column_text(compiledStatement,0)];
}
}
// Release the compiled statement from memory
sqlite3_finalize(compiledStatement);
}
sqlite3_close(database);
}
#catch (NSException * ex) {
#throw ex;
}
#finally {
}
}
You should declare an mutable array as an instance variable something like,
NSMutableArray * colors;
Initialize it in the viewDidLoad method and later alter your retrive1 method to add to the colors array.
-(void)retrive1
{
/* Clearing existing values for newer ones */
[colors removeAllObjects]
/* Get database path */
#try {
[..]
while(sqlite3_step(compiledStatement) == SQLITE_ROW) {
[colors addObject:[NSString stringWithUTF8String:(char*)sqlite3_column_text(compiledStatement,0)]];
}
[..]
}
#catch (NSException * ex) { #throw ex; }
#finally { }
}
And you'll have to implement the rest of the table view methods in the usual manner using the array as the source.
You have to create object with all data and implementation of UITableViewDataSource protocol for table view and set it in TableView property dataSource. After you havecall UITableView method
-(void)reloadData;
i'm using uitextview for searching the contact details from address book. i.e., like uisearchbar search the contact details while text edit change in uitextview.
i'm using uitextview if i tap 'a', the list of the contacts from address book will be display in table view
please give me the solution
Finally I got the solution simple coding here it is
//viewDidLoad
NSMutableArray *personArray = [[NSMutableArray alloc] init];
ABRecordRef personRef;
for (int i = 0; i < CFArrayGetCount(allPeople); i++)
{
personRef = (ABRecordID*)CFArrayGetValueAtIndex(allPeople, i);
ABRecordRef person = ABAddressBookGetPersonWithRecordID(addressBook, ABRecordGetRecordID(personRef));
#try
{
if (ABRecordCopyValue(person, kABPersonBirthdayProperty))
[personArray addObject: (id)personRef];
}
#catch (NSException * e)
{
}
#finally
{
}
NSString *FirstName = [[[NSString stringWithString:(NSString *)ABRecordCopyValue(personRef, kABPersonFirstNameProperty)]stringByAppendingString:#" "]stringByAppendingString:(NSString *)ABRecordCopyValue(personRef, kABPersonLastNameProperty)];
[arr addObject:FirstName];
}
[arr3 addObjectsFromArray:arr];
}
//textviewdidchange
[arr3 removeAllObjects];
NSInteger counter = 0;
for(NSString *name in arr)
{
NSRange r = [name rangeOfString:txtView.text options:NSCaseInsensitiveSearch];
if(r.location != NSNotFound)
{
[arr3 addObject:name];
}
counter++;
}
[table reloadData];
Thanks for your help
I've been trying to return data from a table after already having accessed two before it, but in this case it get's into the while statement but does not assign any values as everything is set to null.
The code is:
NSMutableArray *all_species = [[NSMutableArray alloc] init];
sqlite3 *db_species;
int dbrc_species;
Linnaeus_LiteAppDelegate *appDelegate = (Linnaeus_LiteAppDelegate*) [UIApplication sharedApplication].delegate;
const char* dbFilePathUTF8 = [appDelegate.dbFilePath UTF8String];
dbrc_species = sqlite3_open (dbFilePathUTF8, &db_species);
if (dbrc_species) {
return all_species;
}
sqlite3_stmt *dbps_species;
const char *queryStatement = "SELECT species_id, species_name, species_latin, species_genus FROM \
linnaeus_species;";
if (sqlite3_prepare_v2 (db_species, queryStatement, -1, &dbps_species, NULL) == SQLITE_OK) {
sqlite3_bind_int(dbps_species, 1, [the_species_id intValue]);
while (sqlite3_step(dbps_species) == SQLITE_ROW) {
Species *species = [[Species alloc] init];
NSLog(#"%#", sqlite3_column_int(dbps_species, 0));
[species setSpecies_id:[[NSNumber alloc] initWithInt:sqlite3_column_int(dbps_species, 0)]];
char *new_name = (char *) sqlite3_column_text(dbps_species, 1);
[species setSpecies_name:nil];
if (new_name != NULL) {
[species setSpecies_name:[NSString stringWithUTF8String:(char *) sqlite3_column_text(dbps_species, 1)]];
}
char *new_latin = (char *) sqlite3_column_text(dbps_species, 2);
[species setSpecies_latin:nil];
if (new_latin != NULL) {
[species setSpecies_latin:[NSString stringWithUTF8String:(char *) sqlite3_column_text(dbps_species, 2)]];
}
[species setSpecies_genus:[NSNumber numberWithInt:sqlite3_column_int(dbps_species, 3)]];
[species setEdited:0];
[all_species addObject:species];
[species release];
}
sqlite3_finalize(dbps_species);
}
else {
sqlite3_close(db_species);
}
I've also tried using NSLog(#"Data: %#", sqlite3_column_text(dbps_species, 1)); and it causes a EXC_BAD_ACCESS error which suggests it could be memory related but I can't see why.
NSLog(#"Data: %#", sqlite3_column_text(dbps_species, 1));
Will cause EXC_BAD_ACCESS because the result of sqlite3_column_text is a C string (char*), not an NSString*. To print C strings you need the %s format specifier:
NSLog(#"Data: %s", sqlite3_column_text(dbps_species, 1));
Also, don't waste time to call sqlite3_column_text twice, e.g.
char *new_name = (char *) sqlite3_column_text(dbps_species, 1);
[species setSpecies_name:nil];
if (new_name != NULL) {
[species setSpecies_name:[NSString stringWithUTF8String:new_name]];
}
You could also try using the FMDB classes. These make using sqlite a LOT easier.
http://gusmueller.com/blog/archives/2008/03/fmdb_for_iphone.html