[__NSCFString objectForKey:]: unrecognized selector sent to instance 0xa6a2750 - ios

I converted my database value to JSON format. It's showing in URL as JSON. Then i'm fetching value from JSON URL then store to local database. But i'm getting below error: [__NSCFString objectForKey:]: unrecognized selector sent to instance 0xa6a2750 and *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFString objectForKey:]: unrecognized selector sent to instance 0xa6a2750'
JSON value in URL:
[{"cat_id":"196","category_name":"Performance Parts"},{"cat_id":"212","category_name":"Car Care"}]
Getting value and insert to local:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"Mdb.sqlite"];
NSLog(#"filepath %#",path);
//NSDictionary *jsonDict = [stringFromFileAtURL JSONValue];
//array
NSArray *userData = [str JSONValue];
// NSLog(#"userData is %#", userData);
BOOL notExist = TRUE;
sqlite3_stmt *statement, *addStmt;
for (NSArray *skarray in userData) {
NSLog(#"test");
for (NSDictionary *tuser in skarray) {
NSLog(#"test1");
//write all this in the table
//if already exists in data base id then overwrite the name
//category table
//NSLog(#"CategoryId is %#",[tuser objectForKey:#"cat_id"]);
//NSLog(#"CategoryName is %#",[tuser objectForKey:#"cat_name"]);
if (sqlite3_open([path UTF8String], &database) == SQLITE_OK) {
NSLog(#"test2");
const char *sql = [[NSString stringWithFormat:#"SELECT cat_id FROM categories where cat_id = '%#'",[tuser objectForKey:#"cat_id"]] cStringUsingEncoding:NSUTF8StringEncoding];
NSLog(#"test3");
NSLog(#"check category is %s", sql);
if (sqlite3_prepare_v2(database, sql, -1, &statement, NULL) == SQLITE_OK) {
notExist = TRUE;
while (sqlite3_step(statement) == SQLITE_ROW) {
notExist = FALSE;
}
}
if(notExist){
//NSLog(#"cat id does not exist");
const char *sqlInsert = [[NSString stringWithFormat:#"insert into categories (cat_id, category_name) values ('%#', '%#')", [tuser objectForKey:#"cat_id"], [tuser objectForKey:#"category_name"]] cStringUsingEncoding:NSUTF8StringEncoding];
NSLog(#"Insert category is %s", sqlInsert);
if(sqlite3_prepare_v2(database, sqlInsert, -1, &addStmt, NULL) != SQLITE_OK)
NSAssert1(0, #"Error while creating add statement. '%s'", sqlite3_errmsg(database));
if(SQLITE_DONE != sqlite3_step(addStmt))
NSAssert1(0, #"Error while inserting data. '%s'", sqlite3_errmsg(database));
}
}
}
}

Remove for (NSArray *skarray in userData) { loop and use
for (NSDictionary *tuser in userData) {
NSLog(#"test1");
if (sqlite3_open([path UTF8String], &database) == SQLITE_OK) {
const char *sql = [[NSString stringWithFormat:#"SELECT cat_id FROM categories where cat_id = '%#'",[tuser objectForKey:#"cat_id"]] cStringUsingEncoding:NSUTF8StringEncoding];
if (sqlite3_prepare_v2(database, sql, -1, &statement, NULL) == SQLITE_OK) {
notExist = TRUE;
while (sqlite3_step(statement) == SQLITE_ROW) {
notExist = FALSE;
}
}

You're trying to get data from NSDictionary (or mutable) but in your case, somehow it converts to NSString (NSCFString) and which don't have objectForKey property. Take a look into steps you're compiling where you using objectForKey.

Related

Select data from sqlite iOS has null statement sometime

I am selecting data from sqlite database. Problem is that using following code it works some time. But lets say we call this method for any other table twice then it shows null select statement for other method. Is any thing wrong in method so that if we use same for other tables some time it works some time not.
-(void)getAssessmentNumber:(NSString *)dbPath{
appDelegate=[[UIApplication sharedApplication]delegate];
NSString*fileDBPath=[[NSBundle mainBundle] pathForResource:#"Database" ofType:#"sqlite"];
if (sqlite3_open([fileDBPath UTF8String], &database) == SQLITE_OK)
{
// NSLog(#"%#",[self getDBPath]);
NSString *querySQL = [NSString stringWithFormat:#"Select Am.AssessmentID , Am.AssessmentName From AssessmentMaster Am LEFT JOIN AssessmentDepartmentMapping M ON M.AssessmentID = Am.AssessmentID LEFT JOIN DepartmentListing d ON d.departmentID =M.departmentID where d.departmentID = '%#'",appDelegate.departmentID];
NSLog(#"%#",querySQL);
const char *sql = [querySQL UTF8String];
sqlite3_stmt *selectstmt;
NSError *error;
[appDelegate.assessmentNumberArray removeAllObjects];
if (sqlite3_prepare_v2(database, sql, -1, &selectstmt, NULL) == SQLITE_OK)
{
while (sqlite3_step(selectstmt) == SQLITE_ROW)
{
NSInteger primaryKey = sqlite3_column_int(selectstmt, 0);
AssessmentListening *asmObj = [[AssessmentListening alloc] initWithPrimaryKey:primaryKey];
asmObj.assessmentID=[NSString stringWithFormat:#"%d",primaryKey];
asmObj.assessmentName = [NSString stringWithUTF8String:(char *)sqlite3_column_text(selectstmt, 1)];
[appDelegate.assessmentNumberArray addObject:asmObj];
}
}
else {
NSAssert1(0, #"Failed to create writable database file with message '%#'.", [error localizedDescription]);
}
// sqlite3_finalize(selectstmt);
}
sqlite3_close(database);
}
Is this fine for getting the data from table?
Your code needs a little cleanup.
- (void)getAssessmentNumber:(NSString *)dbPath {
NSString *fileDBPath = [[NSBundle mainBundle] pathForResource:#"Database" ofType:#"sqlite"];
if (sqlite3_open([fileDBPath UTF8String], &database) == SQLITE_OK) {
appDelegate = [[UIApplication sharedApplication] delegate];
[appDelegate.assessmentNumberArray removeAllObjects];
const char *sql = "Select Am.AssessmentID, Am.AssessmentName From AssessmentMaster Am LEFT JOIN AssessmentDepartmentMapping M ON M.AssessmentID = Am.AssessmentID LEFT JOIN DepartmentListing d ON d.departmentID = M.departmentID where d.departmentID = ?";
sqlite3_stmt *selectstmt;
if (sqlite3_prepare_v2(database, sql, -1, &selectstmt, NULL) == SQLITE_OK) {
sqlite3_bind_text(selectstmt, 0, [appDelegate.departmentID UTF8String], -1, SQLITE_TRANSIENT);
while (sqlite3_step(selectstmt) == SQLITE_ROW) {
NSInteger primaryKey = sqlite3_column_int(selectstmt, 0);
AssessmentListening *asmObj = [[AssessmentListening alloc] initWithPrimaryKey:primaryKey];
asmObj.assessmentID = [NSString stringWithFormat:#"%d", primaryKey];
asmObj.assessmentName = [NSString stringWithUTF8String:(char *)sqlite3_column_text(selectstmt, 1)];
[appDelegate.assessmentNumberArray addObject:asmObj];
}
sqlite3_finalize(selectstmt);
} else {
NSLog(#"Unable to prepare statement: %s", sqlite3_errmsg(database));
}
sqlite3_close(database);
} else {
NSLog(#"Unable to open the database from %#: %s", fileDBPath, sqlite3_errmsg(database);
}
}
Note all of the changes:
Only close the database if it is opened.
Only finalize the statement if it is prepared.
Don't build queries with stringWithFormat. Use the proper sqlite3_bind_xxx function to bind the values to the query. This ensures special characters are escaped and properly deals with quoting.
Use proper error checking. Use sqlite3_errmsg to get the error.

iOS - Error connecting to db on real device

I have been working on an Ionic Phonegap project for iOS. There is a method implemented in Appdelegate.m which makes an AJAX request to download a text file from a server, which contains a URL to connect to another server in order for the app to work.
I have made two classes,
WebContent and WebCustomContent
In WebContent.m I insert a particular URL taken from the text file to a sqlite DB and then retrieve it using WebCustomContent.m
Refer to the following code block
-(NSString*)getDataBasePath{
//CHECK
NSString* documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString* foofile = [documentsPath stringByAppendingPathComponent:#"webcontentdb.sqlite"];
BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:foofile];
NSLog(#"%d", fileExists);
//END OF CHECK
//SIMULATOR
NSString *databasePath1 = [[NSBundle mainBundle] pathForResource:#"webcontentdb" ofType:#"sqlite"];
// return databasePath1;
//REAL DEVICE
NSArray* paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString* documentsDirectory = [paths objectAtIndex:0];
NSString* databasePath = [documentsDirectory stringByAppendingPathComponent:#"webcontentdb.sqlite"];
return databasePath;
}
-(void)updateUserAgeRange:(NSString*)age{
NSString* databasePath = [self getDataBasePath];
sqlite3 *database;
if(sqlite3_open([databasePath UTF8String], &database) == SQLITE_OK) {
NSString *query = [NSString stringWithFormat:#"update user_setting set valstr = '%#' where keystr = 'AGE' ", age];
NSLog(#"update %#" , query);
const char * sql = [query UTF8String];
sqlite3_stmt *compiledStatement;
if(sqlite3_prepare_v2(_database, sql, -1, &compiledStatement, NULL) == SQLITE_OK) {
sqlite3_step(compiledStatement); // Here is the added step.
NSLog(#"updateContact SUCCESS - executed command %#",query);
}
else {
NSLog(#"updateContact FAILED - failed to execute command %#",query);
}
sqlite3_finalize(compiledStatement);
}
else {
//NSLog(#"pdateContact FAILED - failed to open database");
}
sqlite3_close(database);
}
- (NSString *)getUserPreferenceValues:(NSString*)keystr {
NSString *retval = [[NSString alloc] init] ;
NSString *query = [NSString stringWithFormat:#"SELECT valstr FROM user_setting where keystr = '%#' " , keystr];
NSLog(#" query %#", query);
sqlite3_stmt *statement;
if (sqlite3_prepare_v2(_database, [query UTF8String], -1, &statement, nil) == SQLITE_OK) {
while (sqlite3_step(statement) == SQLITE_ROW) {
char *nameChars = (char *) sqlite3_column_text(statement, 0 );
NSString *name = [[NSString alloc] initWithUTF8String:nameChars];
NSLog(#" valstr %#", name);
retval = name;
}
sqlite3_finalize(statement);
}
return retval;
}
-(void)insertDatabaseCommonValues:(NSString*)urlstr{
NSString* databasePath = [self getDataBasePath];
sqlite3 *database;
if(sqlite3_open([databasePath UTF8String], &database) == SQLITE_OK) {
NSString *query = [NSString stringWithFormat:#"delete from url_preference"];
const char * sql = [query UTF8String];
sqlite3_stmt *compiledStatement;
if(sqlite3_prepare_v2(_database, sql, -1, &compiledStatement, NULL) == SQLITE_OK) {
sqlite3_step(compiledStatement); // Here is the added step.
// NSLog(#"updateContact SUCCESS - executed command %#",query);
}
else {
//NSLog(#"updateContact FAILED - failed to execute command %#",query);
}
sqlite3_finalize(compiledStatement);
}
else {
//NSLog(#"pdateContact FAILED - failed to open database");
}
//************************************INSERT************************************//
//sqlite3 *database;
if(sqlite3_open([databasePath UTF8String], &database) == SQLITE_OK) {
//NSLog(#"URL STRING %#",urlstr);
NSString *query = [NSString stringWithFormat:#"insert into url_preference (name) values ( '%#' ) ", urlstr];
NSLog(#"inset %#" , query);
const char * sql = [query UTF8String];
sqlite3_stmt *compiledStatement;
NSLog(#" error code.. %d",sqlite3_prepare_v2(_database, sql, -1, &compiledStatement, NULL));
if(sqlite3_prepare_v2(_database, sql, -1, &compiledStatement, NULL) == SQLITE_OK) {
sqlite3_step(compiledStatement); // Here is the added step.
NSLog(#"updateContact SUCCESS - executed command %#",query);
}
else {
NSLog(#"updateContact FAILED - failed to execute command %#",query);
}
sqlite3_finalize(compiledStatement);
}
else {
//NSLog(#"pdateContact FAILED - failed to open database");
}
sqlite3_close(database);
}
Here, when I print the BOOL variable fileExists, it prints YES, meaning the database exists in Documents folder.
But insertion and update queries fail as follows;
2015-06-22 11:18:18.215 App Name[5510:60b] URL http://www.google.lk
2015-06-22 11:18:22.082 App Name[5510:60b] 1
2015-06-22 11:18:24.103 App Name[5510:60b] success to open database!
2015-06-22 11:18:26.197 App Name[5510:60b] 1
2015-06-22 11:18:28.673 App Name[5510:60b] inset insert into url_preference (name) values ( 'http://www.google.lk' )
2015-06-22 11:18:28.676 App Name[5510:60b] error code.. 1
2015-06-22 11:18:28.679 App Name[5510:60b] updateContact FAILED - failed to execute command insert into url_preference (name) values ( 'http://www.google.lk' )
I've placed the database file in the project folder as shown below;
I can't seem to figure out what I'm doing wrong. Please help.
Is it possible this is a file permissions problem? I would suggest right-clicking the webcontentdb.sqlite file in Finder, select Get Info, and under Sharing & Permissions make all users have Read & Write privileges.
If that doesn't work, I would use an SQLite browser app to verify that the database file can be written to and is not corrupted in any way.

Issue in deleting raw from table sqlite

this is what i am doing in header
static sqlite3 *database = nil;
static sqlite3_stmt *deleteStmt = nil;
#implementation SQLAppDelegate
#synthesize window;
#synthesize navigationController;
#synthesize coffeeArray;
this is what i am using for deleting raw
- (void) removeCoffee:(NSNumber *)coffeeObj {
NSLog(#"coffeeObj%#",coffeeObj);
int myInteger = [coffeeObj integerValue];
NSLog(#"myInteger%d",myInteger);
// print this myInteger0
NSLog(#"%#",coffeeArray);
//print object
if (sqlite3_open([self getDBPath], &database) == SQLITE_OK)
{
NSLog(#"myInteger%#",[self getDBPath]);
NSString *sql = [NSString stringWithFormat: #"delete from Coffee where CoffeeID =%d",myInteger];
const char *del_stmt = [sql UTF8String];
NSLog(#"%#",del_stmt); // getting print
// print this delete from Coffee where CoffeeID =0.
sqlite3_prepare_v2(database, del_stmt, -1, & deleteStmt, NULL);
NSLog(#"sqlite3_step(deleteStmt) == SQLITE_DONE%#",sqlite3_step(deleteStmt) == SQLITE_DONE);
// this print null
if (sqlite3_step(deleteStmt) == SQLITE_DONE)
{
//NSLog(#"hi") this is not getting print
} else {
//NSLog(#"hi") this is getting print
}
sqlite3_finalize(deleteStmt);
sqlite3_close(database);
[coffeeArray removeObjectAtIndex:myInteger];
NSLog(#"%#",coffeeArray);
// object is deleted
}
}
my table is like below
table name = Coffee
CoffeeID(INTEGER)=0
CoffeeName(VARCHAR)=Latte
Price(REAL)=2.99
where thing runs perfectly object get deleted from array and thats why its not appearing on table cell. but its not getting deleted from database table thats why it when i launch app again then it shows again please help what i am doing wrong.
Before start deleting the object just conform once the database is opened properly or not. Just try like this.
//Setting path
NSArray *dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *docsDir = [dirPaths objectAtIndex:0];
databasePath = [[NSString alloc] initWithString: [docsDir stringByAppendingPathComponent: #"database.db"]];
const char *dbpath=[databasePath UTF8String];
if (sqlite3_open(dbpath, &database) == SQLITE_OK)
{
NSString *sql = [NSString stringWithFormat: #"delete from Coffee where CoffeeID =%d",myInteger];
const char *del_stmt = [sql UTF8String];
sqlite3_prepare_v2(database, del_stmt, -1, & deleteStmt, NULL);
if (sqlite3_step(deleteStmt) == SQLITE_DONE)
{
} else {
}
sqlite3_finalize(deleteStmt);
sqlite3_close(database);
[coffeeArray removeObjectAtIndex:myInteger];
NSLog(#"%#",coffeeArray);
// object is deleted
}
if(sqlite3_open([[self filepath] UTF8String], &db) == SQLITE_OK)
{
Deletestatement = nil;
if(Deletestatement == nil)
{
const char *sql = "delete from Sqlitemanager2;";
if(sqlite3_prepare_v2(db, sql, -1, &Deletestatement, NULL) != SQLITE_OK)
NSAssert1(0, #"Error while creating delete statement. '%s'", sqlite3_errmsg(db));
}
if (SQLITE_DONE != sqlite3_step(Deletestatement)) //prathibha for problem in if
NSAssert1(0, #"Error while deleting. '%s'", sqlite3_errmsg(db));
sqlite3_finalize(Deletestatement);
}
I hope this will help you.

what does if exist return

I am using sqlite3 as my database for ios project and would like to execute if exist statement to see whether the object exists and if does, update or else insert.
I am using this function to query the database
-(void)updateStatus:(NSString *)queryString {
NSString *docsDir;
NSArray *dirPaths;
dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
docsDir = [dirPaths objectAtIndex:0];
m_singleton = [Singleton sharedSingleton];
strDatabasePath = [NSString stringWithString:[docsDir stringByAppendingPathComponent:#"BorneoMotors.db"]];
NSFileManager *filemgr = [NSFileManager defaultManager];
if ([filemgr fileExistsAtPath: strDatabasePath] == YES)
{
const char *dbpath = [strDatabasePath UTF8String];
if (sqlite3_open(dbpath, &sqlDatabase) == SQLITE_OK)
{
const char* beginString = "BEGIN;";
sqlite3_stmt *compiledstatement;
sqlite3_prepare_v2(sqlDatabase, beginString, -1, &compiledstatement, NULL);
if (sqlite3_step(compiledstatement) == SQLITE_DONE) {}
else NSLog(#"Failed!");
sqlite3_finalize(compiledstatement);
NSLog(#"QUERY : %#",queryString);
const char *selectStatement = [queryString UTF8String];
sqlite3_prepare_v2(sqlDatabase, selectStatement, -1, &compiledstatement, NULL);
//sqlite3_bind_text(compiledstatement,1,[statusString UTF8String],-1,SQLITE_TRANSIENT);
if (sqlite3_step(compiledstatement) == SQLITE_DONE) {}
else NSLog(#"Failed!");
sqlite3_finalize(compiledstatement);
const char* endString="END;";
sqlite3_prepare_v2(sqlDatabase, endString, -1, &compiledstatement, NULL);
if (sqlite3_step(compiledstatement) == SQLITE_DONE) {}
else NSLog(#"Failed!");
sqlite3_finalize(compiledstatement);
sqlite3_close(sqlDatabase);
}
else NSLog(#"Failed to open table");
}
}
The problem i have is that what this if exists will return and how do i move upon that.
NSString *checkstring = [NSString stringWithFormat:#"IF EXISTS (SELECT * FROM DATABASE WHERE id = %#",cars.ID];
DB *accessdb = [[DB alloc] init];
[accessdb updateStatus:checkstring];
if (??){
NSString *queryString = [NSString stringWithFormat: #"UPDATE DATABASE SET STATUS='%#' WHERE \"DATABASEID\" = '%#'", cars.status,cars.ID];
const char *selectStatement = [queryString UTF8String];
sqlite3_prepare_v2(sqlDatabase, selectStatement, -1, &statement, NULL);
//sqlite3_bind_text(compiledstatement,1,[statusString UTF8String],-1,SQLITE_TRANSIENT);
if (sqlite3_step(statement) == SQLITE_DONE) {}
else NSLog(#"Failed!");
sqlite3_finalize(statement);
}else{
insert}
How do i check whether the existence of the object? What does the if exists return? Need some guidance...
SQLite does not have an IF statement.
To check whether some record exist, just execute a query like
SELECT 1 FROM database WHERE ID = ?
and test in your app whether or not you get back a record.
For your update/insert problem: If you have a unique index on the key colum, you could use the INSERT OR REPLACE command which automatically deletes the old record if the new one would create a duplicate.

App crashes when attempting to make an SQLite connection/statement

I'm having an issue with SQLite where my app crashes at run time while I'm trying to make a connection to an SQLite database and grab some of its contents. Here's my code:
-(IBAction)setInput:(id)sender
{
NSString *strStoreNumber;
NSString *strRegNumber;
strStoreNumber = StoreNumber.text;
strRegNumber = RegNumber.text;
lblStoreNumber.text = strStoreNumber;
lblRegNumber.text = strRegNumber;
NSString* databasePath = [[NSBundle mainBundle] pathForResource:#"tblStore" ofType:#"sqlite"];
if(sqlite3_open([databasePath UTF8String], &database) == SQLITE_OK)
{
NSLog(#"Opened sqlite database at %#", databasePath);
//...stuff
}
else
{
NSLog(#"Failed to open database at %# with error %s", databasePath, sqlite3_errmsg(database));
sqlite3_close (database);
}
NSString *querystring;
querystring = [NSString stringWithFormat:#"SELECT strStore FROM tblStore WHERE strStore = %#;", strStoreNumber];
const char *sql = [querystring UTF8String];
NSString *szStore = nil;
NSString *szReg = nil;
sqlite3_stmt *statement = nil;
if (sqlite3_prepare_v2(database, sql, -1, &statement, NULL)!=SQLITE_OK) //queryString = Statement
{
NSLog(#"sql problem occured with: %s", sql);
NSLog(#"%s", sqlite3_errmsg(database));
}
else
{
// you could handle multiple rows here
while (sqlite3_step(statement) == SQLITE_ROW) // queryString = statement
{
szStore = [NSString stringWithUTF8String:(char*)sqlite3_column_text(statement, 0)];
szReg = [NSString stringWithUTF8String:(char*)sqlite3_column_text(statement, 1)];
} // while
}
sqlite3_finalize(statement);
// go on with putting data where you want
}
The errors I'm getting in console:
2012-05-07 09:39:33.619 CCoDBTry[962:f803] Opened sqlite database at /Users/*******/Library/Application Support/iPhone Simulator/5.1/Applications/5DB7A218-A0F6-485F-B366-91FD2F9BC062/CCoDBTry.app/tblStore.sqlite
2012-05-07 09:39:33.623 CCoDBTry[962:f803] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** +[NSString stringWithUTF8String:]: NULL cString'
*** First throw call stack:
(0x1593022 0x1724cd6 0x153ba48 0x153b9b9 0x9d4973 0x27c9 0x1594e99 0xd714e 0xd70e6 0x17dade 0x17dfa7 0x17d266 0xfc3c0 0xfc5e6 0xe2dc4 0xd6634 0x147def5 0x1567195 0x14cbff2 0x14ca8da 0x14c9d84 0x14c9c9b 0x147c7d8 0x147c88a 0xd4626 0x1f82 0x1ef5)
terminate called throwing an exception(lldb)
Any help is greatly appreciated!
EDIT: Note the values I'm looking for in the database are of type VARCHAR. I'm not sure if knowing that makes a difference.
+[NSString stringWithUTF8String:]: NULL cString
It's complaining that you've fed a null value into stringWithUTF8String:. Your code has two calls to this method, each feeding a value in from the query results. Looking at your query, you are only selecting a single column, strStore. I would assume that the line that assigns to szReg is failing because you are trying to retrieve a value that you haven't selected in your query.
For accessing values that may be null and we are not sure about it I generally prefer checking it before hand
char *sk = (char *)sqlite3_column_text(statement, 0);
if (sk != nil) {
szStore = [NSString stringWithUTF8String:sk];
}
This will stop the app from crashing.

Resources