Implicit conversion to an Objective-C pointer using SQLite3 - ios

I following old tutorial that use MRC, and when i pasted code i got an error: Implicit conversion to an Objective-C pointer using SQLite3 on a line:
if (sqlite3_open([sqLiteDb UTF8String], &_database) != SQLITE_OK) {
Full code snippet is :
static FailedBankDatabase *_database;
+ (FailedBankDatabase*)database {
if (_database == nil) {
_database = [[FailedBankDatabase alloc] init];
}
return _database;
}
- (id)init {
if ((self = [super init])) {
NSString *sqLiteDb = [[NSBundle mainBundle] pathForResource:#"banklist"
ofType:#"sqlite3"];
if (sqlite3_open([sqLiteDb UTF8String], &_database) != SQLITE_OK) {
NSLog(#"Failed to open database!");
}
}
return self;
}
Im not very keen in MRC, can you help me fix it?

The _database variable is your static reference to the FailedBankDatabase singleton. But you are also trying to use it to save the SQLite database reference. For that, you need an instance variable of type sqlite3 *.
Update your code to something like the following:
#implementation FailedBankDatabase {
sqlite3 *_db;
}
+ (FailedBankDatabase*)database {
static FailedBankDatabase *database = nil;
if (database == nil) {
database = [[FailedBankDatabase alloc] init];
}
return database;
}
- (id)init {
if ((self = [super init])) {
NSString *sqLiteDb = [[NSBundle mainBundle] pathForResource:#"banklist"
ofType:#"sqlite3"];
if (sqlite3_open([sqLiteDb UTF8String], &_db) != SQLITE_OK) {
NSLog(#"Failed to open database!");
}
}
return self;
}
Now use the _db variable for all database references in the various sqlite3_... function calls.
FYI - you should use a more modern approach to creating the singleton:
+ (FailedBankDatabase*)database {
static FailedBankDatabase *database = nil;
static dispatch_once_t predicate = 0;
dispatch_once(&predicate, ^{
database = [[FailedBankDatabase alloc] init];
});
return database;
}

Related

iOS Tolo bus REGISTER() macro wierd behavior

I have an ordinary Database manager class. Here is the code:
#import "DatabaseManager.h"
#import "Tolo.h"
#import "Action.h"
#import "ActionCreatorConstants.h"
#import <sqlite3.h>
#import "DatabaseConstants.h"
#import "KGKSignal.h"
#interface DatabaseManager ()
#property (nonatomic, strong) NSString *documentsDirectory;
#property (nonatomic, strong) NSString *databaseFilename;
#property (nonatomic, strong) NSMutableArray *arrayResults;
#property (nonatomic, strong) NSMutableArray *arrayColumnNames;
#property (nonatomic) int affectedRows;
#property (nonatomic) long long lastInsertedRowID;
#end
#implementation DatabaseManager
static DatabaseManager *instance = nil;
+ (instancetype)getInstance {
if (instance == nil) {
instance = [[DatabaseManager alloc] initWithDatabaseFilename:DATABASE_NAME];
}
return instance;
}
- (instancetype)initWithDatabaseFilename:(NSString *)databaseFilename {
self = [super init];
if (self) {
REGISTER();
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentationDirectory, NSUserDomainMask, YES);
self.documentsDirectory = [paths objectAtIndex:0];
self.databaseFilename = databaseFilename;
// [self copyDatabaseIntoDocumentsDirectory];
}
return self;
}
- (void)copyDatabaseIntoDocumentsDirectory {
NSString *destinationPath = [self.documentsDirectory stringByAppendingPathComponent:self.databaseFilename];
if (![[NSFileManager defaultManager] fileExistsAtPath:destinationPath]) {
NSString *sourcePath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:self.databaseFilename];
NSError *error;
[[NSFileManager defaultManager] copyItemAtPath:sourcePath
toPath:destinationPath
error:&error];
if (error != nil) {
NSLog(#"%#", [error localizedDescription]);
}
}
}
- (void)runQuery:(const char *)query isQueryExecutable:(BOOL)queryExecutable {
sqlite3 *sqlite3Database;
// NSString *databasePath = [self.documentsDirectory
// stringByAppendingPathComponent:self.databaseFilename];
NSString *databasePath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:DATABASE_NAME];
if (self.arrayResults != nil) {
[self.arrayResults removeAllObjects];
self.arrayResults = nil;
}
self.arrayResults = [[NSMutableArray alloc] init];
if (self.arrayColumnNames != nil) {
[self.arrayColumnNames removeAllObjects];
self.arrayColumnNames = nil;
}
self.arrayColumnNames = [[NSMutableArray alloc] init];
BOOL openDatabaseResult = sqlite3_open([databasePath UTF8String], &sqlite3Database);
if (openDatabaseResult == SQLITE_OK) {
sqlite3_stmt *compiledStatement;
BOOL preparedStatementResult = sqlite3_prepare_v2(sqlite3Database, query, -1,
&compiledStatement, NULL);
if (preparedStatementResult == SQLITE_OK) {
if (!queryExecutable) {
NSMutableArray *arrayDataRow;
while (sqlite3_step(compiledStatement) == SQLITE_ROW) {
arrayDataRow = [[NSMutableArray alloc] init];
int totalColumns = sqlite3_column_count(compiledStatement);
for (int i = 0; i < totalColumns; i++) {
char *dbDataAsChars = (char *)sqlite3_column_text(compiledStatement, i);
if (dbDataAsChars != NULL) {
[arrayDataRow addObject:[NSString stringWithUTF8String:dbDataAsChars]];
}
if (self.arrayColumnNames.count != totalColumns) {
dbDataAsChars = (char *)sqlite3_column_name(compiledStatement, i);
[self.arrayColumnNames addObject:[NSString stringWithUTF8String:dbDataAsChars]];
}
}
if (arrayDataRow.count > 0) {
[self.arrayResults addObject:arrayDataRow];
}
}
} else {
BOOL executeQueryResult = sqlite3_step(compiledStatement);
if (executeQueryResult) {
self.affectedRows = sqlite3_changes(sqlite3Database);
self.lastInsertedRowID = sqlite3_last_insert_rowid(sqlite3Database);
} else {
NSLog(#"Database error: %s", sqlite3_errmsg(sqlite3Database));
}
}
} else {
NSLog(#"%s", sqlite3_errmsg(sqlite3Database));
}
sqlite3_finalize(compiledStatement);
}
sqlite3_close(sqlite3Database);
}
- (NSArray *)loadDataFromDatabase:(NSString *)query {
[self runQuery:[query UTF8String] isQueryExecutable:NO];
return (NSArray *)self.arrayResults;
}
- (void)executeQuery:(NSString *)query {
[self runQuery:[query UTF8String] isQueryExecutable:YES];
}
SUBSCRIBE(Action) {
if ([event.type isEqualToString:GET_LAST_SIGNAL_DATE_FROM_DATABASE]) {
NSLog(#"Lal");
}
}
- (void)insertSignal:(KGKSignal *)signal {
NSString *insertSignalQuery = [NSString stringWithFormat:#"INSERT INTO %# (%#,%#,%#,%#,%#,%#,%#,%#,%#,%#,%#,%#) VALUES (%ld,%ld,%f,%f,%ld,%f,%f,%ld,%ld,%ld,%ld,%ld);", TABLE_SIGNAL, COLUMN_DEVICE_ID, COLUMN_MODE, COLUMN_LATITUDE, COLUMN_LONGITUDE, COLUMN_DATE, COLUMN_VOLTAGE, COLUMN_BALANCE, COLUMN_SATELLITES, COLUMN_SPEED, COLUMN_CHARGE, COLUMN_DIRECTION, COLUMN_TEMPERATURE, (long)signal.deviceId, (long)signal.mode, signal.latitude, signal.longitude, (long)signal.date, signal.voltage, signal.balance, (long)signal.satellites, (long)signal.speed, (long)signal.charge, (long)signal.direction, (long)signal.temperature];
[self executeQuery:insertSignalQuery];
}
- (NSInteger)getLastSignalDate {
NSInteger lastSignalDate = 1441065600;
return lastSignalDate;
}
#end
The problem lurks in the last method - getLastSignalDate. When i set return value to 0 - app works ok. When method returns any non-null number - app craches in runtime (build successful). Error occurs in Tolo object - it can not register (Via REGISTER() macro) Database Manager object - EXC_BAD_ACCESS error in publish method of Tolo.m. Did someone face with same wierd behavior???
I've overriden dealloc method of Database Manager and it didn't log before error occured - so object exists in memory.

Storing custom class object in Sqlite3 database failed

I want to store a custom class MCOIMAPSession object into sqlite3 database. I read about NSKeyedArchiver and trying to use that like below.
- (void) updateImapSessionForAccount :(NSString *) emailAddress :(MCOIMAPSession *)imapSession {
const char *dbpath = [databasePath UTF8String];
//SQLIte Statement
NSString *selettablequery = [NSString stringWithFormat:#"select * from MailBoxInfoDBTable"];
if (sqlite3_open(dbpath, &database) == SQLITE_OK)
{
//if(sqlite3_prepare_v2(database, [selettablequery UTF8String], -1, &statement, NULL) == SQLITE_OK)
if (sqlite3_prepare(database, [selettablequery UTF8String], -1, &statement, NULL) ==SQLITE_OK)
{
// Take an array to store all string.
//NSMutableArray *allRows = [[NSMutableArray alloc] init];
while(sqlite3_step(statement) == SQLITE_ROW)
{
char *emailfield = (char *) sqlite3_column_text(statement,0);
NSString *emailStr = [[NSString alloc] initWithUTF8String: emailfield];
NSLog(#"updateMailMessagesPerAccount: %#", emailStr);
if([emailStr isEqualToString:emailAddress])
{
sqlite3_reset(statement);
NSData *messagesData = [NSKeyedArchiver archivedDataWithRootObject:imapSession];
NSString* stringFromData = [messagesData base64EncodedStringWithOptions:0];
NSString *sqlStr = [NSString stringWithFormat:#"update MailBoxInfoDBTable set imapsession='%#' where emailid='%#'", stringFromData, emailAddress];
const char *updateStatement = [sqlStr UTF8String];
if (sqlite3_prepare(database, updateStatement, -1, &statement, NULL) == SQLITE_OK)
{
if(SQLITE_DONE != sqlite3_step(statement))
NSLog(#"Error while updating. %s", sqlite3_errmsg(database));
sqlite3_finalize(statement);
sqlite3_close(database);
return;
}
else
{
NSLog(#"Error in statement: %s", sqlite3_errmsg(database));
}
}
}
}
sqlite3_finalize(statement);
sqlite3_close(database);
}
}
- (MCOIMAPSession *) retrieveImapSessionForAccount :(NSString *) emailAddress {
MCOIMAPSession *imapsessionObj = nil;
const char *dbpath = [databasePath UTF8String];
//SQLIte Statement
NSString *selettablequery = [NSString stringWithFormat:#"select * from MailBoxInfoDBTable"];
if (sqlite3_open(dbpath, &database) == SQLITE_OK)
{
//if(sqlite3_prepare_v2(database, [selettablequery UTF8String], -1, &statement, NULL) == SQLITE_OK)
if (sqlite3_prepare(database, [selettablequery UTF8String], -1, &statement, NULL) ==SQLITE_OK)
{
// Take an array to store all string.
//NSMutableArray *allRows = [[NSMutableArray alloc] init];
while(sqlite3_step(statement) == SQLITE_ROW)
{
char *emailfield = (char *) sqlite3_column_text(statement, 0);
NSString *emailStr = [[NSString alloc] initWithUTF8String: emailfield];
NSLog(#"retrieveImapSessionForAccount: Email: %#", emailStr);
if([emailStr isEqualToString:emailAddress])
{
//const void *bytes = sqlite3_column_blob(statement, 3);
char *emailstring = (char *) sqlite3_column_text(statement, 3);
if (emailstring) {
NSString *messageStr = [[NSString alloc] initWithUTF8String: emailstring];
NSData *data = [[NSData alloc] initWithBase64EncodedString:messageStr options:NSDataBase64DecodingIgnoreUnknownCharacters];
imapsessionObj = [NSKeyedUnarchiver unarchiveObjectWithData:data];
}
}
}
}
sqlite3_finalize(statement);
sqlite3_close(database);
}
return imapsessionObj;
}
I got crash encodeWithCoder unrecognized selector sent to instance when doing NSKeyedArchiver archivedDataWithRootObject:imapSession
Then, I added the below methods in the 3rd party class MCOIMAPSession.mm file
- (void)encodeWithCoder:(NSCoder *)aCoder{
[aCoder encodeObject:self forKey:#"PROPERTY_KEY"];
}
-(id)initWithCoder:(NSCoder *)aDecoder{
if(self = [super init]){
self = [aDecoder decodeObjectForKey:#"PROPERTY_KEY"];
}
return self;
}
UPDATED: I tried the below as well.
#interface MCOIMAPSession : NSObject
....
#end
#interface NSObject (NSCoding)
-(id)initWithCoder:(NSCoder*)decoder;
-(void)encodeWithCoder:(NSCoder*)encoder;
#end
#endif
#implementation MCOIMAPSession
-(id)initWithCoder:(NSCoder *)decoder {
if ((self=[super initWithCoder:decoder])) {
}
return self;
}
#end
#implementation NSObject (NSCoding)
-(id)initWithCoder:(NSCoder*)decoder {
return [self init];
}
-(void)encodeWithCoder:(NSCoder*)encoder {}
#end
HERE IS THE FILE OF MCOIMAPSESSION MCOIMAPSESSION link .. Please let me know how can i add property now?
But, I see still the same crash. Could someone correct me what i'm doing wrong here when storing custom class MCOIMAPSession object in sqlite database?
Your implementation of the NSCoding methods is incorrect. You don't encode/decode self, you encode/decode each property/ivar of self. Something like:
- (void)encodeWithCoder:(NSCoder *)aCoder{
// Replace the following with the class's actual properties
[aCoder encodeObject:self.propertyA forKey:#"propertyA"];
[aCoder encodeObject:self.propertyB forKey:#"propertyB"];
[aCoder encodeObject:self.propertyC forKey:#"propertyC"];
}
-(id)initWithCoder:(NSCoder *)aDecoder{
if(self = [super init]){
// Replace the following with the class's actual properties
_propertyA = [aDecoder decodeObjectForKey:#"propertyA"];
_propertyB = [aDecoder decodeObjectForKey:#"propertyB"];
_propertyC = [aDecoder decodeObjectForKey:#"propertyC"];
}
return self;
}
BTW - your question has nothing at all to do with SQLite. Your question should be narrowed down just to the problem with the encoding/decoding.
You cannot call encodeWithCoder with object self. You have to encode (and decode) each relevant property of the class MCOIMAPSession.
Edit:
For the MCOIMAPSession the NSCoding methods should look like
- (id)initWithCoder:(NSCoder *)decoder
{
self = [super initWithCoder:decoder]
if (self) {
self.hostname = [decoder decodeObjectForKey:#"hostname"];
self.port = [decoder decodeIntegerForKey:#"port"];
self.username = [decoder decodeObjectForKey:#"username"];
self.password = [decoder decodeObjectForKey:#"password"];
// etc
}
return self;
}
-(void)encodeWithCoder:(NSCoder*)encoder
{
[aCoder encodeObject:self.hostname forKey:#"hostname"];
[aCoder encodeInteger:self.port forKey:#"port"];
[aCoder encodeObject:self.username forKey:#"username"];
[aCoder encodeObject:self.password forKey:#"password"];
// etc
}
Add all properties you need. And consider that properties representing instances of other custom classes must be also NSCoding compliant.

sqlite3 prepare statement not working, possibly improper pointers iOS

I have setup a GlobalVars class to hold my sqlite3 database variable.
static sqlite3** database;
const char *dbPath;
#implementation GlobalVars : NSObject
+(GlobalVars*)sharedInstance {
static GlobalVars *myInstance = nil;
if(myInstance == nil) {
myInstance = [[[self class] alloc] init];
}
return myInstance;
}
+(sqlite3*)getGlobalDatabase {
return &database;
}
+(void)setGlobalDatabase:(sqlite3*)_database {
database = &_database;
}
Then in the header file I have
static sqlite3** database;
which is above the interface. This is how I setup my database variable.
I am then trying to access it when i open the database and prepare it. I can open it, because the open call returns true. I can not prepare it properly, because the statement returns false and it doesn't go into the if statement. I am wondering if I have messed up my pointers, because the prepare statement isn't working, and it doesn't prepare it properly.
-(void)setAllValues:(NSMutableArray*)array {
if(sqlite3_open([GlobalVars getGlobalDBPath], [GlobalVars getGlobalDatabase]) == SQLITE_OK) {
sqlite3_stmt *insertStatement;
NSString *sqlInsert = [NSString stringWithFormat:#"insert into my_table ('_id', 'name', 'age', 'weight', 'height', 'description') VALUES (%i, '%#', '%i', '%i', '%#', '%#')", ID, name, age, weight, height, description];
//*********** This is not opening, and SQLITE_OK is equal to false ***********
if(sqlite3_prepare_v2(([GlobalVars getGlobalDatabase]), [sqlInsert UTF8String], -1, &insertStatement, nil) == SQLITE_OK) {
if(sqlite3_step(insertStatement) == SQLITE_DONE) {
NSLog(#"insert stepping done");
}
sqlite3_reset(insertStatement);
}
sqlite3_finalize(insertStatement);
sqlite3_close([GlobalVars getGlobalDatabase]);
}
}
The variables for the database are all filled with their correct data, and it seems to open the database without issues. When it comes to preparing, it does not work properly and returns false. Any ideas why. Thank you for your assistance, any help is appreciated.
**
You must try this one ... Maybe its help you :
**
#import "DBManager.h"
#import "userRegistrationClass.h"
static DBManager *sharedInstance = nil;
static sqlite3 *database = nil;
static sqlite3_stmt *statement = nil;
#implementation DBManager
#pragma mark
#pragma mark Get shared Function
+(DBManager*)getSharedInstance{
if (!sharedInstance) {
sharedInstance = [[super allocWithZone:NULL]init];
[sharedInstance createDB];
}
return sharedInstance;
}
#pragma mark
#pragma mark Create DataBase
-(BOOL)createDB{
NSString *docsDir;
NSArray *dirPaths;
// Get the documents directory
// http://www.mycashkit.com/my-earnings.php
dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSLog(#"Dir Path Value is %#",dirPaths);
docsDir = [dirPaths objectAtIndex:0];
NSLog(#"DocsDir Path Value is %#",docsDir);
// Build the path to the database file
databasePath = [[NSString alloc] initWithString:[docsDir stringByAppendingPathComponent: #"UserRegInfo.sqlite"]];
NSLog(#"Data base Work's %#:",databasePath);
BOOL isSuccess = YES;
NSFileManager *filemgr = [NSFileManager defaultManager];
// NSString *currentPath = [filemgr currentDirectoryPath];
NSLog(#"My file managaer value is %#",filemgr);
//NSLog(#"My current drictory path is %#",currentPath);
//the file will not be there when we load the application for the first time
//so this will create the database table
if ([filemgr fileExistsAtPath: databasePath ] == NO)
{
const char *dbpath = [databasePath UTF8String];
NSLog(#"Constan charcter value is %s:-",dbpath);
if (sqlite3_open(dbpath, &database) == SQLITE_OK)
{
char *errMsg;
const char *sql_stmt = "create table if not exists UserInfo(UserID integer primary key, UserName,Gender,UserEmailID,Password,RePassword,DOB, MobileNo,IsUserType)";
const char *sql_stmt2 = "create table if not exists TestInfo(TestID integer primary key, TestName,TestType)";
// NSString *dbPathFromApp=[[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"UserRegInfo.sqlite"];[filemgr copyItemAtPath:dbPathFromApp toPath:databasePath error:nil];
NSLog(#"Constan charcter value is %s:-",dbpath);
if (sqlite3_exec(database, sql_stmt, NULL, NULL, &errMsg) && (sqlite3_exec(database, sql_stmt2, NULL, NULL, &errMsg)!= SQLITE_OK))
{
isSuccess = NO;
NSLog(#"Failed to create table");
}
NSLog(#"Print Sqlite%d",(sqlite3_exec(database, sql_stmt, NULL, NULL, &errMsg)));
sqlite3_close(database);
return isSuccess;
}
else {
isSuccess = NO;
NSLog(#"Failed to open/create database");
}
}
return isSuccess;
}
#pragma mark
#pragma mark Save Data Function
-(BOOL)saveData:(NSString*)insertSQL{
const char *dbpath = [databasePath UTF8String];
if (sqlite3_open(dbpath, &database) == SQLITE_OK)
{
NSLog(#" my Sqlite Query is :- %#",insertSQL);
const char *insert_stmt = [insertSQL UTF8String];
sqlite3_prepare_v2(database, insert_stmt,-1, &statement, NULL);
if (sqlite3_step(statement) == SQLITE_DONE)
{
return YES;
}
else
{
NSLog(#"Squlite Error Msg is %s",sqlite3_errmsg(database));
return NO;
}
}
return NO;
}

Singleton in static library in iOS

I have a static library which contains a Singleton class (FMDB SQLite Data Access), now I open from my main application the connection and do thingss... this works, after that a method in my library want to call the a method on my singleton and I get the error that
-[FMDatabase executeQuery:withArgumentsInArray:]: message sent to deallocated instance 0xa443960
is this not possible what I'm trying to achieve?
this is short version of my singleton
static MySingleton* _sharedMySingleton = nil;
FMDatabase *database;
#ifndef __clang_analyzer__
+(MySingleton*)sharedMySingleton
{
#synchronized([MySingleton class])
{
if (!_sharedMySingleton)
[[self alloc] init];
return _sharedMySingleton;
}
}
#endif
+(id)alloc
{
#synchronized([MySingleton class])
{
NSAssert(_sharedMySingleton == nil, #"Attempted to allocate a second instance of a singleton.");
_sharedMySingleton = [super alloc];
return _sharedMySingleton;
}
}
-(Resource *)getResourceForName:(NSString *)name
{
NSString *select = #"SELECT Data, MimeType FROM File WHERE FileName = ? LIMIT 1";
NSArray *arguments = [NSArray arrayWithObject:[NSString stringWithFormat:#"/%#", name]];
FMResultSet *s = [database executeQuery:select withArgumentsInArray:arguments];
if (s == NULL)
{
FuncFileLog(#"getResourceForName file cant be loaded: %#", [database lastErrorMessage]);
return nil;
}
NSData *data = nil;
NSString *mimeType;
while ([s next])
{
data = [NSData dataFromBase64String:[s stringForColumnIndex:0]];
mimeType = [s stringForColumnIndex:1];
}
Resource *resource = [[[Resource alloc] initWithData:data mimeType:mimeType] autorelease];
return resource;
}
-(BOOL)openDatabase
{
database = [FMDatabase databaseWithPath:[self getDocumentResourcePath]];
return [database open];
}
-(void)closeDatabase
{
[database close];
[database release];
}
-(void)dealloc
{
if (database != NULL)
{
[self closeDatabase];
}
[baseUrl release];
[super dealloc];
}
#end
EDIT:
I found that the dealloc from FMDatabase gets called after my application start return, but dont know why.
EDIT2:
Currently I thought one problem was this line
database = [FMDatabase databaseWithPath:[self getDocumentResourcePath]];
here I have to retain the object.
You don't actually assign the singleton instance:
if (!_sharedMySingleton)
[[self alloc] init];
should be:
if (!_sharedMySingleton)
_sharedMySingleton = [[self alloc] init];
and dump that overridden alloc method.
Also database should be an instance variable in the class, and not at global scope.

Creating a singleton DB helper class

I am trying to write a Master-Detail application that gets it's data from a sqlite database. As part of this I'm trying to create a helper class that creates a singleton instance of my database. All I want it to do is initialise the database so I can then reference this from the different views of the application.
I followed a tutorial that does this here: http://www.raywenderlich.com/913/sqlite-101-for-iphone-developers-making-our-app
I got the tutorial to work however now I am trying to modify it to fit my application and I can't seem to get it working. I have no errors or warnings but when I run the app on the emulator none of the debug text I have put in executes. So it looks to me like my init function is not executing. I just can't figure out why.
Can anyone spot my problem in the code below?
LoyaltyProgramDatabase.h
#import <Foundation/Foundation.h>
#import <sqlite3.h>
#interface LoyaltyProgramDatabase : NSObject {
sqlite3 *_loyaltyProgDB;
}
#property (strong, nonatomic) NSString *databasePath; //Path file of our database
#property (nonatomic) sqlite3 *loyaltyProgDB; //Reference to the database
+ (LoyaltyProgramDatabase*)loyaltyProgDB;
#end
LoyaltyProgramDatabase.m
#import "LoyaltyProgramDatabase.h"
#implementation LoyaltyProgramDatabase
static LoyaltyProgramDatabase *_loyaltyProgDB;
//Create a singleton instance of loyaltyProgDB
+ (LoyaltyProgramDatabase*)loyaltyProgDB {
if (_loyaltyProgDB == nil) {
_loyaltyProgDB = [[LoyaltyProgramDatabase alloc] init];
}
return _loyaltyProgDB;
}
- (id)init {
NSLog(#"Inside init function");
if ((self = [super init])) {
NSString *docsDir;
NSArray *dirPaths;
// Get the documents directory
dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
docsDir = dirPaths[0];
// Build the path to the database file
_databasePath = [[NSString alloc] initWithString: [docsDir stringByAppendingPathComponent:#"loyaltyProg.db"]];
NSFileManager *filemgr = [NSFileManager defaultManager];
if ([filemgr fileExistsAtPath: _databasePath ] == NO)
{
const char *dbpath = [_databasePath UTF8String];
if (sqlite3_open(dbpath, &_loyaltyProgDB) == SQLITE_OK)
{
char *errMsg;
const char *sql_stmt = "CREATE TABLE IF NOT EXISTS scoreCard (ID INTEGER PRIMARY KEY AUTOINCREMENT, campaignID INTEGER, merchantName TEXT)";
if (sqlite3_exec(_loyaltyProgDB, sql_stmt, NULL, NULL, &errMsg) != SQLITE_OK)
{
//_status.text = #"Failed to create table";
NSLog(#"Failed to create table");
}
sqlite3_close(_loyaltyProgDB);
} else {
//_status.text = #"Failed to open/create database";
NSLog(#"Failed to open/create database");
}
}
}
return self;
}
- (void)dealloc {
sqlite3_close(_loyaltyProgDB);
}
#end
Try this:
+ (id)allocWithZone:(NSZone *)zone
{
return [self loyaltyProgDB];
}
+ (LoyaltyProgramDatabase*)loyaltyProgDB
{
static BNRImageStore *loyaltyProgDB = nil;
if (!loyaltyProgDB) {
// Create the singleton
loyaltyProgDB = [[super allocWithZone:NULL] init];
}
return loyaltyProgDB;
}
- (id)init {
self = [super init];
if (self) {
NSString *docsDir;
NSArray *dirPaths;
// Get the documents directory
dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
docsDir = dirPaths[0];
// Build the path to the database file
_databasePath = [[NSString alloc] initWithString: [docsDir stringByAppendingPathComponent:#"loyaltyProg.db"]];
NSFileManager *filemgr = [NSFileManager defaultManager];
if ([filemgr fileExistsAtPath: _databasePath ] == NO)
{
const char *dbpath = [_databasePath UTF8String];
if (sqlite3_open(dbpath, &_loyaltyProgDB) == SQLITE_OK)
{
char *errMsg;
const char *sql_stmt = "CREATE TABLE IF NOT EXISTS scoreCard (ID INTEGER PRIMARY KEY AUTOINCREMENT, campaignID INTEGER, merchantName TEXT)";
if (sqlite3_exec(_loyaltyProgDB, sql_stmt, NULL, NULL, &errMsg) != SQLITE_OK)
{
//_status.text = #"Failed to create table";
NSLog(#"Failed to create table");
}
sqlite3_close(_loyaltyProgDB);
} else {
//_status.text = #"Failed to open/create database";
NSLog(#"Failed to open/create database");
}
}
}
return self;
}
If you have not written a line of code that says [[LoyaltyProgramDatabase alloc] init] or [LoyaltyProgramDatabase loyaltyProgDB], then your init function is never getting called.
The init is not automatically called when you start the app. The only time any init function is called automatically is if you have a UI element in a nib/xib/storyboard file, and the app creates the element utilizing various initialization functions, but never your own init function. But for something like what you have written, to initialize the database object, you need to call the init function yourself.
In your app delegate, under the didFinishLaunching function, put this line:
[LoyaltyProgramDatabase loyaltyProgDB];
This isn't a really up-to-date singleton pattern by the way. This is actually a lazy loader function. If you want a more secure singleton, use this code.
+(id)sharedInstance {
static dispatch_once_t pred = 0;
__strong static id _sharedObject = nil;
dispatch_once(&pred, ^{
_sharedObject = [[self alloc] init];
});
return _sharedObject;
}
This will make sure the database is only ever initialized once and it is thread safe. To create/use the singleton, the code would change from the above to
[LoyaltyProgramDatabase sharedInstance]

Resources